严格模式触发我的减速器功能两次,这是预期的。
我没想到的是返回的状态中有重复的元素。
我意识到我没有正确使用useReducer,但我不知道如何正确重写我的reducer函数。
下面的示例应在初始渲染时显示 1 个时间戳,然后每次单击
Add Element
时,应添加 1 个额外时间戳。
发生的情况(使用严格模式)是每次单击按钮都会添加 2 个额外的时间戳。
import { useReducer } from 'react';
const reducer = (state, action) => {
if (action.type === 'addElement') {
let newState = { ...state };
newState.elements.push({
id: (new Date()).toString()
})
return newState;
}
}
export default function Test() {
const [state, dispatch] = useReducer(reducer, {
elements: [
{ id: (new Date()).toString() }
]
});
function addElement() {
dispatch({
type: 'addElement'
});
}
return (
<>
<h2>Elements</h2>
{[...Array(state.elements.length)].map((e, i) => <div key={i}>
<span>{state.elements[i].id}</span><br />
</div>
)}
<button type='button' onClick={addElement}>Add Element</button>
</>
);
}
.push()
方法直接改变原始状态数组,即使您分散了状态的其余部分。.push()
,而是将现有数组展开到新数组中并使用 [...state.elements, newElement]
添加新元素。const reducer = (state, action) => {
if (action.type === 'addElement') {
return {
...state,
elements: [...state.elements, { id: new Date().toString() }]
};
}
return state;
};
来自“严格模式触发了我的减速器功能两次,这是预期的。”从代码中可以明显看出,您将两次推入数组,这是无意的副作用。
React
StrictMode
组件重新运行某些生命周期方法并挂钩两次,以帮助您检测代码中的逻辑问题/错误。
请参阅旧版文档中的检测意外副作用,它在解释更详细的细节方面做得更好。我已经强调了相关点。
严格模式无法自动为你检测副作用,但它 可以通过使它们更具确定性来帮助您发现它们。 这是通过有意双重调用以下函数来完成的:
- 类组件
、constructor
和render
方法shouldComponentUpdate
- 类组件静态
方法getDerivedStateFromProps
- 功能组件体
- 状态更新器函数(
的第一个参数)setState
- 传递给
的函数、useState
或useMemo
useReducer
reducer 函数执行了两次,问题是您直接改变当前状态对象。在 React 中,我们从不直接改变状态和属性。您应该更新代码以应用不可变更新模式,即浅复制正在更新的所有状态和嵌套状态。 Array.push 直接推入源数组并对其进行变异。
您可以使用 Spread 语法来复制数组,或使用 Array.concat 追加并返回 new 数组引用。
示例:
const reducer = (state, action) => {
switch(action.type) {
case 'addElement':
return {
...state, // <-- shallow copy state,
elements: [ // <-- new array reference
...state.elements, // <-- shallow copy array
{ // <-- append new data
id: (new Date()).toString()
}
],
};
default:
return state;
}
}
const reducer = (state, action) => {
switch(action.type) {
case 'addElement':
return {
...state, // <-- shallow copy state,
elements: state.elements.concat({ // <-- append new data, return new array
id: (new Date()).toString()
}),
};
default:
return state;
}
}
另外,仅供参考,一般不建议使用日期作为 GUID。最好使用为此设计的库。 Nano ID 是一个很棒的库,可用于快速生成足够唯一的全局 ID 值。