为啥反应上下文提供程序组件呈现两次[重复]
Posted
技术标签:
【中文标题】为啥反应上下文提供程序组件呈现两次[重复]【英文标题】:Why react context provider component renders twice [duplicate]为什么反应上下文提供程序组件呈现两次[重复] 【发布时间】:2020-08-15 08:55:59 【问题描述】:我在玩 React Context API,发现提供程序在每次值更改时呈现两次。
这就是我所做的。
-
创建了一个上下文,然后是一个呈现其提供者的组件。
提供程序提供状态值及其设置器。
创建了一个直接渲染其子级的直接子级。
创建了一个消费者,它读取上下文值并添加一个按钮来更改它。
每个组件在呈现时都会执行一个 console.log。
为提供程序添加了一个效果,无需在每次呈现时都记录日志。
在提供程序中添加了一个 ref,该 ref 在每次渲染时递增,并在渲染和效果中记录。
问题?
每次点击按钮更改上下文值时,提供程序渲染两次,但效果只执行一次。
所以 ref 总是递增两次,但效果每次只获取最后一个值(它跳过一个值!)。
此外,在提供程序的第一次渲染时,它会记录两次相同的 ref 值,这对我来说很奇怪。
谁能告诉我为什么会出现这种行为?
代码如下:
提供者:
const MyContext = React.createContext(0);
function Provider( children )
const state = React.useState("Yes");
const ref = React.useRef(0);
ref.current += 1;
console.log("Context provider ", ref.current);
React.useEffect(() =>
console.log("effect on provider, ref value = ", ref.current);
);
return <MyContext.Provider value=state>children</MyContext.Provider>;
两个孩子
function DirectChild( children )
console.log("provider direct child");
return children;
function Consumer()
console.log("consumer");
const [state, setState] = React.useContext(MyContext);
return (
<div>
<span>State value: state</span>
<br />
<button onClick=() => setState(old => old + "Yes")>Change</button>
</div>
);
应用程序
export default function App()
console.log("APP");
return (
<Provider>
<DirectChild>
<Consumer />
</DirectChild>
</Provider>
);
这是codesandbox demo
【问题讨论】:
将状态逻辑移到应用层,现在行为也在App
,渲染两次,记录两次,只有一个效果,这里是a demo
我的理解是 refs 用于引用 Dom 对象,而不是 state refs(即useState
)。我想你可以用它们来引用任何东西,只是不确定这是他们的意图:"avoid using refs for anything that could be done declaratively".
是的,refs 旨在创建一个可变对象,您可以随意改变它。我找到了这背后的原因,我现在会发布答案;在代码框里是 React.strictMode
并且只影响开发模式
是的,我怀疑是这样的:)我上周左右回答了一个类似的问题......
【参考方案1】:
找到原因,
没有错误,也没有奇怪的行为,我只是错过了默认情况下在 React.StrictMode
父级中呈现应用程序的代码框。
首先,我将代码移植到本地项目,然后观察到没有问题。
搜索了codesandbox repo问题,发现它与严格模式下的反应行为有关:
预计 setState 更新程序将在开发中以严格模式运行两次。这有助于确保代码不依赖于它们一次运行(如果异步渲染被中止并重新启动,则不会出现这种情况)。如果您的 setState 更新程序是纯函数(它们应该是),那么这不应该影响您的应用程序的逻辑。
Codesandbox issue
React issue
但是,效果只执行一次,错过了我的参考更新。
【讨论】:
如果你想跟踪 ref 值,你可以使用React.useCallback
这是示例` const ref = React.useRef(0);让 setRef = React.useCallback(setValue => ref.current = setValue(ref.current); console.log(ref.current) , []) React.useEffect(() => setRef(old => old + 1) , [状态[0]]);`以上是关于为啥反应上下文提供程序组件呈现两次[重复]的主要内容,如果未能解决你的问题,请参考以下文章
包含Context.Provider和Context.Consumer的反应上下文测试组件