[包括useContext钩子使子代的useState重置为初始值
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[包括useContext钩子使子代的useState重置为初始值相关的知识,希望对你有一定的参考价值。
我已经为这个问题苦苦挣扎了几天,所以任何帮助将不胜感激。我们拥有一个全局数据上下文,该上下文包含在层次结构中的一些组件中。我已经复制了以下基本示例中遇到的问题。
问题是,每次重新渲染childValue
组件中的Content
都会重置为其初始useState
值。但这是[[only的情况,当useData
上下文包含在Routes
组件的链中。删除useData
行(并硬编码isAuthenticated
)可以解决此问题。但是,这不是可接受的解决方案,因为我们需要能够将某些值保留在全局范围内,并在任何地方包括它们。
React.memo(...)
中的内容包装无济于事。我在这里想念什么?import React, { useState, useContext, useEffect } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { render } from "react-dom";
// Routes
const Routes = () => {
// We see desired behavior if useData() is removed here.
// i.e. Initial Value does NOT get reset in Content
const { isAuthenticated } = useData();
// const isAuthenticated = true // uncomment this after removing the above line
const RouteComponent = isAuthenticated ? PrivateRoute : Route;
return (
<Switch>
<RouteComponent path="/" render={props => <Content {...props} />} />
</Switch>
);
};
const PrivateRoute = ({ render: Render, path, ...rest }) => (
<Route
path={path}
render={props => <Render isPrivate={true} {...props} />}
{...rest}
/>
);
// Data Context
export const DataContext = React.createContext();
export const useData = () => useContext(DataContext);
export const DataProvider = ({ children }) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [contextValue, setContextValue] = useState(false);
useEffect(() => {
setIsAuthenticated(true);
}, []);
const doSomethingInContext = () => {
setTimeout(() => setContextValue(!contextValue), 1000);
};
return (
<DataContext.Provider
value={{
isAuthenticated,
doSomethingInContext,
contextValue
}}
>
{children}
</DataContext.Provider>
);
};
// Page Content
const Content = props => {
const { contextValue, doSomethingInContext } = useData();
const [childValue, setChildValue] = useState("Initial Value");
useEffect(() => {
if (childValue === "Value set on Click") {
doSomethingInContext();
setChildValue("Value set in useEffect");
}
}, [childValue]);
return (
<div>
<div style={{ fontFamily: "monospace" }}>contextValue:</div>
<div>{contextValue.toString()}</div>
<br />
<div style={{ fontFamily: "monospace" }}>childValue:</div>
<div>{childValue}</div>
<br />
<button onClick={() => setChildValue("Value set on Click")}>
Set Child Value
</button>
</div>
);
};
const App = () => {
return (
<DataProvider>
<Router>
<Routes />
</Router>
</DataProvider>
);
};
render(<App />, document.getElementById("root"));
doSomethingInContext
时,它将触发setContextValue
(在超时后)。运行该命令时,它将更新Provider
的数据,这会导致Routes
重建(因为它是使用者)。重建Routes
会更改render
功能,导致所有下面的东西都被丢弃并重建。尝试useCallback
:在Routes
中,添加以下内容:// In the body...
const render = useCallback(
props => <Content {...props} />,
[]
);
// In the RouteComponent
<RouteComponent path="/" render={render} />
那样,功能不会改变,并且子项应保留在重建中。
以上是关于[包括useContext钩子使子代的useState重置为初始值的主要内容,如果未能解决你的问题,请参考以下文章
如何将 React 钩子(useContext、useEffect)与 Apollo 反应钩子(useQuery)结合起来
使用新的 React 钩子 useContext 的正确方法是啥?
在使用数据库数据更新上下文后,React 'useContext' 钩子不会重新渲染