簡體   English   中英

React Router V6 在路由更改時重新渲染

[英]React Router V6 Re-renders on Route Change

當我在路由之間來回導航時,React Router 會重新渲染記憶的路由,導致useEffect(() => [])重新運行並重新獲取數據。 我想防止這種情況發生,而是保留現有路線但隱藏在dom中。 不過,我正在為“如何”而苦苦掙扎。

以下是該問題的示例代碼:

import React, { useEffect } from "react";
import { BrowserRouter as Router, Route, Routes, useNavigate } from "react-router-dom";

export default function App() {
  return (
    <Router>
      <Routes>
        <Route path={"/"} element={<MemoizedRouteA />} />
        <Route path={"/b"} element={<MemoizedRouteB />} />
      </Routes>
    </Router>
  );
}

function RouteA() {
  const navigate = useNavigate()
  useEffect(() => {
    alert("Render Router A");
  }, []);

  return (
      <button onClick={() => { navigate('/b') }}>Go to B</button>
  );
};

const MemoizedRouteA = React.memo(RouteA)

function RouteB() {
  const navigate = useNavigate()

  useEffect(() => {
    alert("Render Router B");
  }, []);

  return (
    <button onClick={() => { navigate('/') }}>Go to A</button>
  );
}

const MemoizedRouteB = React.memo(RouteB)

沙盒: https://codesandbox.io/s/wonderful-hertz-w9qoip?file=/src/App.js

使用上面的代碼,您將看到每當您點擊按鈕或使用瀏覽器后退按鈕時都會調用“警報”代碼。

多年來,React Router 發生了如此多的變化,我正在努力尋找解決方案。

當我在路由之間來回導航時,React Router 會重新渲染記憶的路由,導致useEffect(() => [])重新運行並重新獲取數據。 我想防止這種情況發生,而是保留現有路線但隱藏在dom中。 不過,我正在為“如何”而苦苦掙扎。

長話短說,你不能。 React 組件出於以下三個原因之一重新渲染:

  1. 本地組件 state 已更新。
  2. 傳遞的道具值被更新。
  3. 父/祖先組件更新。

使用memo HOC 的原因在這里不起作用,因為Routes組件一次只匹配和呈現單個Route組件的element prop。 "/"導航到"/b"必然會卸載MemoizedRouteA並安裝MemoizedRouteB ,反之亦然。 這正是 RRD 的工作方式。 這就是 React 組件生命周期的工作方式。 在安裝/卸載組件時,記住組件 output 無法執行任何操作。

如果您真正想要最小化/減少/避免的是組件安裝時重復的異步調用和數據獲取/重新獲取,那么我在這里建議的是應用Lifting State Up模式並將 state 和useEffect調用移動到父級/祖先。

這是一個使用Outlet組件及其提供的上下文的簡單示例,但 state 可以通過任何其他方式提供,例如常規 React 上下文或 Redux。

import React, { useEffect, useState } from "react";
import {
  BrowserRouter as Router,
  Route,
  Routes,
  Outlet,
  useNavigate,
  useOutletContext
} from "react-router-dom";

export default function App() {
  const [users, setUsers] = useState(0);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((response) => response.json())
      .then(setUsers);
  }, []);

  return (
    <Router>
      <Routes>
        <Route element={<Outlet context={{ users }} />}>
          <Route path={"/"} element={<RouteA />} />
          <Route path={"/b"} element={<RouteB />} />
        </Route>
      </Routes>
    </Router>
  );
}

function RouteA() {
  const navigate = useNavigate();

  return (
    <div>
      <button onClick={() => navigate("/b")}>Go to B</button>
    </div>
  );
}

function RouteB() {
  const navigate = useNavigate();
  const { users } = useOutletContext();

  return (
    <div>
      <button onClick={() => navigate("/")}>Go to A</button>
      <ul>
        {users.map((user) => (
          <li key={user.id}>
            {user.name} : {user.email}
          </li>
        ))}
      </ul>
    </div>
  );
}

編輯 react-router-v6-re-renders-on-route-change

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM