欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

背景

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

目標:封裝keepalive緩存組件,實現(xiàn)組件的緩存,并暴露相關方法,可以手動清除緩存。

版本: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(
    // 緩存滾動條
    (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維護所有緩存信息, dispatch派發(fā)修改緩存狀態(tài)*/}
      {Object.values(cacheStates)
        .filter((cacheState) => cacheState.status !== cacheTypes.DESTROY)
        .map(({ cacheId, element }) => (
          <div
            id={`cache_${cacheId}`}
            key={cacheId}
            // 原生div中聲明ref,當div渲染到頁面,會執(zhí)行ref中的回調(diào)函數(shù),這里在id為cache_${cacheId}的div渲染完成后,會繼續(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)聽緩存組件的滾動事件,調(diào)用handleScroll()緩存滾動條
        ref.current.addEventListener(
          "scroll",
          handleScroll.bind(null, cacheId),
          true
        );
      }
    }, [handleScroll]);
    useEffect(() => {
      let cacheState = cacheStates[cacheId];
      if (
        cacheState &&
        cacheState.doms &&
        cacheState.status !== cacheTypes.DESTROY
      ) {
        // 如果真實dom已經(jīng)存在,且狀態(tài)不是DESTROY,則用當前的真實dom
        let doms = cacheState.doms;
        doms.forEach((dom) => ref.current.appendChild(dom));
        if (scroll) {
          // 如果scroll = true, 則將緩存中的scrollTop拿出來賦值給當前dom
          doms.forEach((dom) => {
            if (cacheState.scrolls[dom])
              dom.scrollTop = cacheState.scrolls[dom];
          });
        }
      } else {
        // 如果還沒產(chǎn)生真實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>將目標緩存組件或者父級包裹;

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

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ù)據(jù),即回到首頁,需要清除列表頁的緩存。

上面的KeepAliveProvider.js中,暴露了一個useCacheContext()的hook,該hook返回了緩存組件相關數(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)完成啦~

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

相關文章

  • 深入淺析react native es6語法

    深入淺析react native es6語法

    這篇文章主要介紹了深入淺析react native es6語法的相關資料,需要的朋友可以參考下
    2015-12-12
  • React實現(xiàn)路由返回攔截的三種方式

    React實現(xiàn)路由返回攔截的三種方式

    最近項目為了避免用戶誤操作導致數(shù)據(jù)丟失,增加返回攔截功能,但是之前由于qiankun的報錯導致這個功能一直有一些問題,所以專門獨立搞了一個專題研究在react中各種方式實現(xiàn)這個功能,需要的朋友可以參考下
    2024-05-05
  • React 服務器組件的使用方法詳解

    React 服務器組件的使用方法詳解

    最近,React 服務器組件受到了廣泛的關注和熱捧,這是因為 React 服務器組件允許開發(fā)人員將與組件相關的任務外包給服務器,在本文中,我們將討論什么是 React 服務器組件,以及如何將它們集成到構(gòu)建應用程序中,需要的朋友可以參考下
    2023-10-10
  • React中getDefaultProps的使用小結(jié)

    React中getDefaultProps的使用小結(jié)

    React中的getDefaultProps功能允許開發(fā)者為類組件定義默認屬性,提高組件的靈活性和容錯性,本文介紹了getDefaultProps的作用、語法以及最佳實踐,并探討了其他替代方案,如函數(shù)組件中的默認參數(shù)、高階組件和ContextAPI等,理解這些概念有助于提升代碼的可維護性和用戶體驗
    2024-09-09
  • ahooks封裝cookie?localStorage?sessionStorage方法

    ahooks封裝cookie?localStorage?sessionStorage方法

    這篇文章主要為大家介紹了ahooks封裝cookie?localStorage?sessionStorage的方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • 從零開始最小實現(xiàn)react服務器渲染詳解

    從零開始最小實現(xiàn)react服務器渲染詳解

    這篇文章主要介紹了從零開始最小實現(xiàn)react服務器渲染詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • 淺談箭頭函數(shù)寫法在ReactJs中的使用

    淺談箭頭函數(shù)寫法在ReactJs中的使用

    這篇文章主要介紹了淺談箭頭函數(shù)寫法在ReactJs中的使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • React星星評分組件的實現(xiàn)

    React星星評分組件的實現(xiàn)

    評分插件在購物的應用中經(jīng)??梢钥吹玫?,但是用著別人的總是沒有自己寫的順手,本文就使用React實現(xiàn)星星評分組件,感興趣的可以了解一下
    2021-06-06
  • React this.setState方法使用原理分析介紹

    React this.setState方法使用原理分析介紹

    我們知道,在React中沒有像Vue那種數(shù)據(jù)雙向綁定的效果。而this.setState方法就是用來對數(shù)據(jù)進行更改的。而通過this.setState方法更改的數(shù)據(jù),會讓組件的render重新渲染,并且刷新數(shù)據(jù)
    2022-09-09
  • React如何以Hook的方式使用Echarts

    React如何以Hook的方式使用Echarts

    這篇文章主要介紹了React如何以Hook的方式使用Echarts問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03

最新評論