提问人:webbyweb 提问时间:5/4/2020 最后编辑:webbyweb 更新时间:5/5/2020 访问量:468
React hook useRender 调用两次,如果之后 bailing 和 setting state
React hook useRender called twice if bailing and setting state afterward
问:
我不确定这是否是预期的行为,但是如果您在使用 useReducer 钩子时退出调度 (https://reactjs.org/docs/hooks-reference.html#bailing-out-of-a-dispatch),则如果操作后跟渲染,则该操作会发生两次。让我解释一下:
// bailing out to prevent re-rendering
const testReducer = (state, action) => {
switch (action.type) {
case "ADD":
state.test += 1
return state;
}
};
const myComponent = () => {
let [totalClicks, setClicks] = useState(0);
const [state, setState] = useReducer(testReducer, {
test: 0,
});
const clickHandler = () => {
setState({type: 'ADD'});
setClicks((totalClicks += 1));
};
return (
<div>
<button onClick={clickHandler}>+</button>
<p>{totalClicks}</p>
<p>test count: {state.test}</p>
</div>
);
}
单击该按钮时,state.test 将增加 2,而 totalClicks 将增加 1。但是,如果我要更改减速器,使其不会像下面那样,它们都会增加 1。
// non-bailing reducer
const testReducer = (state, action) => {
switch (action.type) {
case "ADD":
return {
test: state.test + 1,
};
}
};
为什么会这样?这是预期的行为还是错误? 沙盒示例:https://codesandbox.io/s/sad-robinson-dds63?file=/src/App.js
更新:在进行一些调试后,似乎只有在使用 React.StrictMode 包装时才会发生此行为
有谁知道是什么原因造成的???
答:
1赞
hackape
5/5/2020
#1
根据 StrictMode 的文档,react 故意以相同的动作调用 reducer 函数两次,从而暴露未被注意到的潜在有害副作用,这正是您的情况。
严格模式无法自动为您检测副作用,但它可以通过使它们更具确定性来帮助您发现它们。这是通过有意重复调用以下函数来完成的:[...]传递给 useState、useMemo 或 useReducer 的函数
评论
0赞
webbyweb
5/5/2020
哇,这很有趣。那么这个例子是不安全的呢?是不是我们在同一个点击事件上更新了我们的 useState 状态和 useReducer 状态?
0赞
hackape
5/5/2020
这是关于你违反了一个假设,即 reducer 应该是无副作用的、幂等的,并且在发生更改时总是返回新值。你违反了第三条规则(虽然是故意的)。对我来说,这更像是一个惯例。但是,由于围绕这一假设建立了一大堆生态系统和机制(如救助),因此它成为一种要求。所以 strictMode 决定公开它。
评论