考虑以下代码:
https://codesandbox.io/p/sandbox/hardcore-lake-mptzw3
App.jsx:
import ContextProvider from "./provider/contextProvider";
import Routes from "./routes";
function App() {
console.log("In App");
return (
<ContextProvider>
<Routes />
</ContextProvider>
);
}
export default App;
路由.jsx:
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { provideContext } from "./provider/contextProvider";
import Component1 from "./pages/Component1";
import Component2 from "./pages/Component2";
const Routes = () => {
const { token } = provideContext();
const router = createBrowserRouter([
{
path: "/Component2",
element: <Component2 />,
},
{
path: "/Component1",
element: <Component1 />,
},
]);
return <RouterProvider router={router} />;
};
export default Routes;
pages/Component1.jsx:
const Component1 = () => {
console.log("In Component1");
return <div>Component1</div>;
};
export default Component1;
pages/Component2.jsx:
import { useNavigate } from "react-router-dom";
import { provideContext } from "../provider/contextProvider";
const Component2 = () => {
const navigate = useNavigate();
const { setToken } = provideContext();
console.log("In Component2");
const onClick = () => {
setToken("Token");
setTimeout(() => {
navigate("/Component1");
});
};
return (
<>
<button onClick={onClick}>Click me</button>
</>
);
};
export default Component2;
提供者/ContextProvider.jsx:
import { createContext, useContext, useState } from "react";
const Context = createContext();
const ContextProvider = ({ children }) => {
const [token, setToken] = useState("Initial");
return (
<Context.Provider value={{ token, setToken }}>{children}</Context.Provider>
);
};
export const provideContext = () => {
return useContext(Context);
};
export default ContextProvider;
点击
Component2
中的按钮时,URL发生变化,但UI仍然显示Component2.
Component 1
甚至没有渲染一次。
有趣的是,如果我删除
setTimeout()
函数中的 Component2.jsx
或删除 const { token } = provideContext();
中的 Routes.jsx
,问题就会消失。不知道发生了什么。
问题是在 ReactTree 内声明路由器。
要么移动声明路由器外部ReactTree:
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { provideContext } from "./provider/ContextProvider";
import Component1 from "./pages/Component1";
import Component2 from "./pages/Component2";
const router = createBrowserRouter([
{
path: "/Component2",
element: <Component2 />,
},
{
path: "/Component1",
element: <Component1 />,
},
]);
const Routes = () => {
const { token } = provideContext();
return <RouterProvider router={router} />;
};
export default Routes;
或者记忆路由器,这样当上下文状态更新时,它就不会在每个渲染周期中重新声明:
import { useMemo } from "react";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { provideContext } from "./provider/ContextProvider";
import Component1 from "./pages/Component1";
import Component2 from "./pages/Component2";
const Routes = () => {
const { token } = provideContext();
const router = useMemo(() =>
createBrowserRouter([
{
path: "/Component2",
element: <Component2 />,
},
{
path: "/Component1",
element: <Component1 />,
},
]), [] // <-- add any required dependencies here
);
return <RouterProvider router={router} />;
};
export default Routes;
您确实不需要使用
setTimeout
来发出导航操作。删除 setTimeout
中的 Component2
。
import { useNavigate } from "react-router-dom";
import { provideContext } from "../provider/ContextProvider";
const Component2 = () => {
const navigate = useNavigate();
const { setToken } = provideContext();
const onClick = () => {
setToken("Token");
navigate("/Component1");
};
return (
<>
<button onClick={onClick}>Click me</button>
</>
);
};
export default Component2;