REACT - évitez le nouveau rendu de la page sur le bouton post-navigateur
P粉733166744
P粉733166744 2024-03-27 14:50:53
0
1
438

J'ai une page de catalogue qui montre beaucoup de produits, une fois que l'utilisateur clique sur l'un des produits qu'il peut choisir en bas, disons le numéro de produit 1000, il passe à une autre page, vérifie le contenu etc... et quand il utilise le bouton Retour Lorsque le navigateur revient à la page du catalogue, tout est à nouveau rendu, ce qui est logique, mais prend beaucoup de temps pour positionner la barre de défilement sur le produit précédemment sélectionné.

Lorsque l'utilisateur sélectionne un certain produit (par exemple le produit numéro 4) en haut de la page, tout fonctionne bien, mais lorsqu'il va en bas, le scénario démarre.

Existe-t-il un moyen de mettre en cache cette page de répertoire dans REACT ? Pour éviter le temps de rendu ?

La pagination en bas de la page table des matières résout ce problème, mais j'ai un bouton "charger plus". J'ai essayé d'utiliser React.memo mais cela ne fonctionne que lorsque j'effectue une action sur la page actuelle, pas lorsque j'arrive sur la page à l'aide du bouton Précédent.

J'utilise React Router v5. Je pourrais ajouter du codepen avec le code ici, mais j'aimerais d'abord savoir si cela est possible afin de pouvoir prendre une direction. J'ai vu des pages qui doivent même tout restituer après un retour en arrière avec le bouton Précédent, qui ressemblent à une page statique et le défilement ne se déplace même pas jusqu'à l'endroit où le dernier produit a été sélectionné. Y a-t-il de la lumière dans l'obscurité ?

C'est mon exemple.

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;

Accueil.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

répondre à tous(1)
P粉762447363

Question

Il y a donc certaines choses qui jouent contre vous dans l'application.

  1. Les données sont récupérées et stockées dans l'état local du composant vers lequel vous accédez. Une fois que l'application navigue vers un autre itinéraire, les données sont perdues et réacquises au retour.
  2. Il y a beaucoup de données à restituer.

Solutions possibles suggérées

Pour résoudre le problème de persistance de l'état, la solution ici est de promouvoir l'état en ancêtre commun afin qu'il dure plus longtemps que le composant routé en cours de rendu. Dans un composant parent App ou un composant fournisseur React Context personnalisé, cela suffit.

Exemple :

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

Pour résoudre le problème de la quantité de données à restituer, vous pouvez vous tourner vers la virtualisation ou le fenêtrage. react-window est celui qui s'occupe de ce problème. Cela fait qu'au lieu de restituer l'ensemble des données (potentiellement des milliers d'éléments) dans le DOM, cela ne restitue que ce qui tient à l'écran avec un "surbalayage" avant et après. Exemple :

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

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

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

Une dernière chose à corriger est de revenir à des éléments spécifiques.

Possibilité de faire défiler jusqu'à un index spécifique. Nous pouvons mettre à jour le CardDataContext pour maintenir un certain état de défilement, et mettre à jour le composant Page1 pour définir et restaurer la 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)}>
)}
)}
); };
react-window 能够滚动到特定索引。我们可以更新 CardDataContext 以保持某些滚动状态,并更新 Page1Démo

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal