最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React中實(shí)現(xiàn)keepalive組件緩存效果的方法詳解

 更新時(shí)間:2023年01月14日 09:13:28   作者:coder__wang  
由于react官方并沒有提供緩存組件相關(guān)的api(類似vue中的keepalive),在某些場景,會(huì)使得頁面交互性變的很差。所以本文為大家介紹了React中實(shí)現(xiàn)keepalive組件緩存效果的方法,希望對(duì)大家有所幫助

背景

由于react官方并沒有提供緩存組件相關(guān)的api(類似vue中的keepalive),在某些場景,會(huì)使得頁面交互性變的很差,比如在有搜索條件的表格頁面,點(diǎn)擊某一條數(shù)據(jù)跳轉(zhuǎn)到詳情頁面,再返回表格頁面,會(huì)重新請(qǐng)求數(shù)據(jù),搜索條件也將清空,用戶得重新輸入搜索條件,再次請(qǐng)求數(shù)據(jù),大大降低辦公效率,如圖:

目標(biāo):封裝keepalive緩存組件,實(shí)現(xiàn)組件的緩存,并暴露相關(guān)方法,可以手動(dòng)清除緩存。

版本:React 17,react-router-dom 5

結(jié)構(gòu)

代碼

cache-types.js

// 緩存狀態(tài)
export const CREATE = 'CREATE';        // 創(chuàng)建
export const CREATED = 'CREATED';      // 創(chuàng)建成功
export const ACTIVE = 'ACTIVE';        // 激活
export const DESTROY = 'DESTROY';      // 銷毀

CacheContext.js

import React from 'react';
const CacheContext = React.createContext();
export default CacheContext;

KeepAliveProvider.js

import React, { useReducer, useCallback } from "react";
import CacheContext from "./CacheContext";
import cacheReducer from "./cacheReducer";
import * as cacheTypes from "./cache-types";
function KeepAliveProvider(props) {
  let [cacheStates, dispatch] = useReducer(cacheReducer, {});
  const mount = useCallback(
    ({ cacheId, element }) => {
      // 掛載元素方法,提供子組件調(diào)用掛載元素
      if (cacheStates[cacheId]) {
        let cacheState = cacheStates[cacheId];
        if (cacheState.status === cacheTypes.DESTROY) {
          let doms = cacheState.doms;
          doms.forEach((dom) => dom.parentNode.removeChild(dom));
          dispatch({ type: cacheTypes.CREATE, payload: { cacheId, element } }); // 創(chuàng)建緩存
        }
      } else {
        dispatch({ type: cacheTypes.CREATE, payload: { cacheId, element } }); // 創(chuàng)建緩存
      }
    },
    [cacheStates]
  );
  let handleScroll = useCallback(
    // 緩存滾動(dòng)條
    (cacheId, { target }) => {
      if (cacheStates[cacheId]) {
        let scrolls = cacheStates[cacheId].scrolls;
        scrolls[target] = target.scrollTop;
      }
    },
    [cacheStates]
  );
  return (
    <CacheContext.Provider
      value={{ mount, cacheStates, dispatch, handleScroll }}
    >
      {props.children}
      {/* cacheStates維護(hù)所有緩存信息, dispatch派發(fā)修改緩存狀態(tài)*/}
      {Object.values(cacheStates)
        .filter((cacheState) => cacheState.status !== cacheTypes.DESTROY)
        .map(({ cacheId, element }) => (
          <div
            id={`cache_${cacheId}`}
            key={cacheId}
            // 原生div中聲明ref,當(dāng)div渲染到頁面,會(huì)執(zhí)行ref中的回調(diào)函數(shù),這里在id為cache_${cacheId}的div渲染完成后,會(huì)繼續(xù)渲染子元素
            ref={(dom) => {
              let cacheState = cacheStates[cacheId];
              if (
                dom &&
                (!cacheState.doms || cacheState.status === cacheTypes.DESTROY)
              ) {
                let doms = Array.from(dom.childNodes);
                dispatch({
                  type: cacheTypes.CREATED,
                  payload: { cacheId, doms },
                });
              }
            }}
          >
            {element}
          </div>
        ))}
    </CacheContext.Provider>
  );
}
const useCacheContext = () => {
  const context = React.useContext(CacheContext);
  if (!context) {
    throw new Error("useCacheContext必須在Provider中使用");
  }
  return context;
};
export { KeepAliveProvider, useCacheContext };

withKeepAlive.js

import React, { useContext, useRef, useEffect } from "react";
import CacheContext from "./CacheContext";
import * as cacheTypes from "./cache-types";
function withKeepAlive(
  OldComponent,
  { cacheId = window.location.pathname, scroll = false }
) {
  return function (props) {
    const { mount, cacheStates, dispatch, handleScroll } =
      useContext(CacheContext);
    const ref = useRef(null);
    useEffect(() => {
      if (scroll) {
        // scroll = true, 監(jiān)聽緩存組件的滾動(dòng)事件,調(diào)用handleScroll()緩存滾動(dòng)條
        ref.current.addEventListener(
          "scroll",
          handleScroll.bind(null, cacheId),
          true
        );
      }
    }, [handleScroll]);
    useEffect(() => {
      let cacheState = cacheStates[cacheId];
      if (
        cacheState &&
        cacheState.doms &&
        cacheState.status !== cacheTypes.DESTROY
      ) {
        // 如果真實(shí)dom已經(jīng)存在,且狀態(tài)不是DESTROY,則用當(dāng)前的真實(shí)dom
        let doms = cacheState.doms;
        doms.forEach((dom) => ref.current.appendChild(dom));
        if (scroll) {
          // 如果scroll = true, 則將緩存中的scrollTop拿出來賦值給當(dāng)前dom
          doms.forEach((dom) => {
            if (cacheState.scrolls[dom])
              dom.scrollTop = cacheState.scrolls[dom];
          });
        }
      } else {
        // 如果還沒產(chǎn)生真實(shí)dom,派發(fā)生成
        mount({
          cacheId,
          element: <OldComponent {...props} dispatch={dispatch} />,
        });
      }
    }, [cacheStates, dispatch, mount, props]);
    return <div id={`keepalive_${cacheId}`} ref={ref} />;
  };
}
export default withKeepAlive;

index.js

export { KeepAliveProvider } from "./KeepAliveProvider";
export {default as withKeepAlive} from './withKeepAlive';

使用

1.用<KeepAliveProvider></KeepAliveProvider>將目標(biāo)緩存組件或者父級(jí)包裹;

2.將需要緩存的組件,傳入withKeepAlive方法中,該方法返回一個(gè)緩存組件;

3.使用該組件;

App.js

import React from "react";
import {
  BrowserRouter,
  Link,
  Route,
  Switch,
} from "react-router-dom";
import Home from "./Home.js";
import List from "./List.js";
import Detail from "./Detail.js";
import { KeepAliveProvider, withKeepAlive } from "./keepalive-cpn";

const KeepAliveList = withKeepAlive(List, { cacheId: "list", scroll: true });

function App() {
  return (
    <KeepAliveProvider>
      <BrowserRouter>
        <ul>
          <li>
            <Link to="/">首頁</Link>
          </li>
          <li>
            <Link to="/list">列表頁</Link>
          </li>
          <li>
            <Link to="/detail">詳情頁A</Link>
          </li>
        </ul>
        <Switch>
          <Route path="/" component={Home} exact></Route>
          <Route path="/list" component={KeepAliveList}></Route>
          <Route path="/detail" component={Detail}></Route>
        </Switch>
      </BrowserRouter>
    </KeepAliveProvider>
  );
}

export default App;

效果:

假設(shè)有個(gè)需求,從首頁到列表頁,需要清空搜索條件,重新請(qǐng)求數(shù)據(jù),即回到首頁,需要清除列表頁的緩存。

上面的KeepAliveProvider.js中,暴露了一個(gè)useCacheContext()的hook,該hook返回了緩存組件相關(guān)數(shù)據(jù)和方法,這里可以用于清除緩存:

Home.js

import React, { useEffect } from "react";
import { DESTROY } from "./keepalive-cpn/cache-types";
import { useCacheContext } from "./keepalive-cpn/KeepAliveProvider";

const Home = () => {
  const { cacheStates, dispatch } = useCacheContext();

  const clearCache = () => {
    if (cacheStates && dispatch) {
      for (let key in cacheStates) {
        if (key === "list") {
          dispatch({ type: DESTROY, payload: { cacheId: key } });
        }
      }
    }
  };
  useEffect(() => {
    clearCache();
    // eslint-disable-next-line
  }, []);
  return (
    <div>
      <div>首頁</div>
    </div>
  );
};

export default Home;

效果

至此,react簡易版的keepalive組件已經(jīng)完成啦~

到此這篇關(guān)于React中實(shí)現(xiàn)keepalive組件緩存效果的方法詳解的文章就介紹到這了,更多相關(guān)React keepalive組件緩存效果內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • react 不用插件實(shí)現(xiàn)數(shù)字滾動(dòng)的效果示例

    react 不用插件實(shí)現(xiàn)數(shù)字滾動(dòng)的效果示例

    這篇文章主要介紹了react 不用插件實(shí)現(xiàn)數(shù)字滾動(dòng)的效果示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • react如何實(shí)現(xiàn)側(cè)邊欄聯(lián)動(dòng)頭部導(dǎo)航欄效果

    react如何實(shí)現(xiàn)側(cè)邊欄聯(lián)動(dòng)頭部導(dǎo)航欄效果

    這篇文章主要介紹了react如何實(shí)現(xiàn)側(cè)邊欄聯(lián)動(dòng)頭部導(dǎo)航欄效果,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • React 錯(cuò)誤邊界組件的處理

    React 錯(cuò)誤邊界組件的處理

    這篇文章主要介紹了React 錯(cuò)誤邊界組件的處理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • React hook 'useState' is called conditionally報(bào)錯(cuò)解決

    React hook 'useState' is calle

    這篇文章主要為大家介紹了React hook 'useState' is called conditionally報(bào)錯(cuò)解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • 詳解react-navigation6.x路由庫的基本使用

    詳解react-navigation6.x路由庫的基本使用

    最近兩個(gè)項(xiàng)目都用到了React Navigation,所以就研究一下如何使用,本文主要介紹了react-navigation6.x路由庫的基本使用,感興趣的可以了解一下
    2021-11-11
  • 詳解react中useCallback內(nèi)部是如何實(shí)現(xiàn)的

    詳解react中useCallback內(nèi)部是如何實(shí)現(xiàn)的

    前幾天有人在問在useCallback函數(shù)如果第二個(gè)參數(shù)為空數(shù)組, 為什么拿不到最新的state值,那么這一章就來分析一下useCallback內(nèi)部是如何實(shí)現(xiàn)的,感興趣的小伙伴跟著小編一起來學(xué)習(xí)吧
    2023-07-07
  • react?事項(xiàng)懶加載的三種方法及使用場景

    react?事項(xiàng)懶加載的三種方法及使用場景

    這篇文章主要介紹了react?事項(xiàng)懶加載的三種方法及使用場景,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • React應(yīng)用中使用Bootstrap的方法

    React應(yīng)用中使用Bootstrap的方法

    本篇文章主要介紹了React應(yīng)用中使用Bootstrap的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • 詳解React之key的使用和實(shí)踐

    詳解React之key的使用和實(shí)踐

    這篇文章主要介紹了詳解React之key的使用和實(shí)踐,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-09-09
  • react-native android狀態(tài)欄的實(shí)現(xiàn)

    react-native android狀態(tài)欄的實(shí)現(xiàn)

    這篇文章主要介紹了react-native android狀態(tài)欄的實(shí)現(xiàn),使?fàn)顟B(tài)欄顏色與App顏色一致,使用戶界面更加整體。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-06-06

最新評(píng)論

汪清县| 五莲县| 聊城市| 万山特区| 白沙| 永善县| 禹州市| 清丰县| 唐海县| 鹤山市| 梅河口市| 华容县| 元氏县| 万宁市| 奉贤区| 仪陇县| 东海县| 当雄县| 白城市| 湘乡市| 囊谦县| 厦门市| 五指山市| 塔城市| 嫩江县| 嘉鱼县| 青河县| 桃园县| 临颍县| 石城县| 邛崃市| 石屏县| 芷江| 宁德市| 文登市| 安远县| 安福县| 长沙县| 元阳县| 临城县| 时尚|