我有一個(gè)顯示很多產(chǎn)品的目錄頁面,一旦使用者點(diǎn)擊他可能從底部選擇的產(chǎn)品之一,比如說產(chǎn)品編號(hào)1000,他就會(huì)轉(zhuǎn)到另一個(gè)頁面,檢查內(nèi)容等...並且當(dāng)當(dāng)他使用後退按鈕瀏覽器返回目錄頁面時(shí),所有內(nèi)容都會(huì)再次呈現(xiàn),這是有道理的,但需要花費(fèi)大量時(shí)間將滾動(dòng)條定位到先前選擇的產(chǎn)品。
當(dāng)使用者在頁面頂部選擇某個(gè)產(chǎn)品(例如產(chǎn)品編號(hào) 4)時(shí),一切都運(yùn)作良好,但當(dāng)他轉(zhuǎn)到底部時(shí),場(chǎng)景就開始了。
有什麼辦法可以在 REACT 中快取這個(gè)目錄頁面嗎?為了避免渲染所需的時(shí)間?
目錄頁面底部的分頁解決了此問題,但我有一個(gè)「加載更多」按鈕。我嘗試使用 React.memo,但它僅在我在當(dāng)前頁面上執(zhí)行操作時(shí)有效,而不是在我使用後退按鈕登陸頁面時(shí)有效。
我正在使用React Router v5。我可以在此處添加一些帶有代碼的代碼筆,但首先我想知道這是否可行,以便採(cǎi)取一些方向。我看到頁面甚至需要在使用後退按鈕返回後渲染所有內(nèi)容,看起來像靜態(tài)頁面,並且滾動(dòng)甚至不會(huì)移動(dòng)到最後選擇的產(chǎn)品的位置。黑暗中還有光嗎?
這是我的例子。
App.jsx
##import React, { StrictMode } from 'react'; import { BrowserRouter, Switch, Route, Link } from 'react-router-dom' import './App.css'; import Home from './Home'; import Page1 from './Page1'; import Page2 from './Page2'; function App() { return ( <StrictMode> <BrowserRouter> <div className="App"> <header className="App-header"> <Link to='/'>home</Link><br /> <Link to='/page1'>page 1</Link><br /> <Link to='/page2'>page 2</Link><br /> </header> <Switch> <Route path='/page1'> <Page1 /> </Route> <Route path='/page2'> <Page2 /> </Route> <Route path='/'> <Home /> </Route> </Switch> </div> </BrowserRouter> </StrictMode> ); } export default App;
Home.jsx
#import React from 'react'; const Home = () => <h1>This is the home</h1> export default Home;
Page1.jsx
import React, { useEffect, useState } from 'react'; import Card from './Card'; const Page1 = () => { const [cards, setCards] = useState([]); const fetchData = () => { fetch('https://jsonplaceholder.typicode.com/photos') .then((response) => response.json()) .then((json) => setCards(json)) .then(() => scrollToElement()); } const scrollToElement = () => { const id = localStorage.getItem('idRef'); if (id) { var access = document.getElementById(id); access.scrollIntoView(); } } useEffect(() => { fetchData() }, []) return ( <div className="grid"> {cards.map((item) => <Card item={item} key={item.id}/>)} </div> ) } export default Page1;
Page2.jsx
import React from 'react'; const Page2 = () => <h1>Product selected... now click back browser button</h1> export default Page2;
因此,應(yīng)用程式中存在一些對(duì)您不利的因素。
為了解決狀態(tài)持久性問題,這裡的解決方案是將狀態(tài)提升到共同祖先的模式,使其比正在渲染的路由元件持續(xù)更長(zhǎng)時(shí)間。在父 App
元件中或自訂 React Context 提供者元件就足夠了。
範(fàn)例:
import { createContext, useContext, useEffect, useState } from "react"; const CardDataContext = createContext({ cards: [], }); const useCardData = () => useContext(CardDataContext); const CardDataProvider = ({ children }) => { const [cards, setCards] = useState([]); const fetchData = () => { fetch("https://jsonplaceholder.typicode.com/photos") .then((response) => response.json()) .then((json) => setCards(json)); }; useEffect(() => { fetchData(); }, []); return ({children} ); };
export default function App() { return (); }home
page 1
page 2
//
為了解決需要渲染的資料量問題,您可以轉(zhuǎn)向虛擬化或視窗化。 react-window
就是處理這個(gè)問題的一個(gè)。其作用是,它不會(huì)將整個(gè)資料數(shù)組(可能有數(shù)千個(gè)元素)渲染到 DOM,而是僅渲染適合螢?zāi)坏膬?nèi)容以及前後的一些「過度掃描」。
範(fàn)例:
import { FixedSizeList as List } from "react-window"; import AutoSizer from "react-virtualized-auto-sizer"; const Page1 = () => { const { cards } = useCardData(); return (); };{({ height, width }) => ( {({ index, style }) => (
)})}
最後要解決的一件事是滾動(dòng)恢復(fù)到特定元素。 react-window
能夠捲動(dòng)到特定索引。我們可以更新 CardDataContext
以保持某些滾動(dòng)狀態(tài),並更新 Page1
元件以設(shè)定和恢復(fù)位置。
const CardDataContext = createContext({ cards: [], scrollIndex: null, setScrollIndex: () => {} }); ... const CardDataProvider = ({ children }) => { ... const [scrollIndex, setScrollIndex] = useState(null); ... return ({children} ); };
const Page1 = () => { const { cards, scrollIndex, setScrollIndex } = useCardData(); const listRef = useRef(); useEffect(() => { if (scrollIndex) { setTimeout(() => { listRef.current.scrollToItem(scrollIndex, "center"); }); } }, [scrollIndex]); return (); };{({ height, width }) => ( {({ index, style }) => (
)}setScrollIndex(index)}>)}