REACT - avoid page re-rendering on post-browser button
P粉733166744
P粉733166744 2024-03-27 14:50:53
0
1
464

I have a catalog page that shows a lot of products, once the user clicks on one of the products he may choose from the bottom, say product number 1000, he goes to another page, checks the content etc... and when When he uses the back button browser to return to the catalog page, everything renders again, which makes sense, but takes a lot of time to position the scroll bar to the previously selected product.

Everything works fine when the user selects a certain product at the top of the page (e.g. product number 4), but when he goes to the bottom, the scenario starts.

Is there any way to cache this directory page in REACT? To avoid the time it takes to render?

Pagination at the bottom of the table of contents page solves this problem, but I have a "load more" button. I tried using React.memo but it only works when I perform an action on the current page, not when I land on the page using the back button.

I'm using React Router v5. I could add some codepen with the code here, but first I'd like to know if this is possible so I can take some direction. I've seen pages that even need to render everything after going back with the back button, look like a static page, and the scrolling doesn't even move to where the last product was selected. Is there light in the darkness?

This is my example.

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;

P粉733166744
P粉733166744

reply all(1)
P粉762447363

question

So there is something working against you in the application.

  1. The data is fetched and stored in the local state of the component being navigated to. Once the app navigates to another route, the data is lost and reacquired on return.
  2. There is a large amount of data that needs to be rendered.

Possible Suggested Solutions

To solve the state persistence problem, the solution here is to promote the state to a common ancestor so that it lasts longer than the routed component being rendered. In the parent App component or a custom React Context provider component is enough.

Example:

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
//
); }

To solve the problem of the amount of data that needs to be rendered, you can turn to virtualization or windowing. react-window is the one that deals with this problem. What this does is, it doesn't render the entire array of data (potentially thousands of elements) to the DOM, but only renders what fits on the screen with some "overscanning" before and after.

Example:

import { FixedSizeList as List } from "react-window";
import AutoSizer from "react-virtualized-auto-sizer";

const Page1 = () => {
  const { cards } = useCardData();

  return (
    
{({ height, width }) => ( {({ index, style }) => (
)}
)}
); };

One last thing to fix is ​​scrolling back to a specific element. react-window Ability to scroll to a specific index. We can update the CardDataContext to maintain some scroll state, and update the Page1 component to set and restore the position.

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)}>
)}
)}
); };

Demo

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template