当您有涉及多个子值的复杂状态逻辑时,或者当下一个状态依赖于前一个状态时,useReducer通常比useState更可取。useReducer还允许优化触发深度更新的组件的性能,因为可以传递分派而不是回调。
(引用自https://reactjs.org/docs/hooks-reference.html#usereducer)
我对粗体部分感兴趣,它指出在上下文中使用useReducer而不是useState。
我尝试了这两种变体,但它们似乎并没有不同。
我比较这两种方法的方式如下:
const [state, updateState] = useState();
const [reducerState, dispatch] = useReducer(myReducerFunction);我将它们中的每一个传递给一个上下文对象,这个对象在一个更深的子对象中使用(我只是运行单独的测试,用我想要测试的函数替换这个值)。
<ContextObject.Provider value={updateState // dispatch}>
这个孩子包含了这些功能
const updateFunction = useContext(ContextObject);
useEffect(
() => {
console.log('effect triggered');
console.log(updateFunction);
},
[updateFunction]
);在这两种情况下,当父级重新命名(因为另一个本地状态更改)时,效果都不会运行,这意味着更新函数在呈现之间没有改变。我读错了引文中的粗体句子吗?还是有什么东西我忽略了?
发布于 2019-02-12 09:25:25
useReducer还允许您优化触发深度更新的组件的性能,因为可以传递分派而不是回调。
上述语句并不试图表明useState返回的setter是在每次更新或呈现时新建的。它的意思是,当您有一个要更新状态的复杂逻辑时,您就不会直接使用setter来更新状态,而是编写一个复杂的函数,然后用更新的状态调用setter,类似于
const handleStateChange = () => {
// lots of logic to derive updated state
updateState(newState);
}
ContextObject.Provider value={{state, handleStateChange}}>现在,在上述情况下,每次重新呈现父实例时,都会创建handleStateChange的新实例,从而导致上下文使用者也重新呈现。
解决上述情况的一个解决方案是使用useCallback并回溯状态更新器方法并使用它。但是,对于这一点,您需要处理与使用方法中的值相关的闭包问题。
因此,建议使用useReducer,它返回一个在重新呈现之间不发生更改的dispatch方法,并且您可以在还原器中使用操作逻辑。
发布于 2019-06-22 09:29:07
当你需要关心它的时候
如果在呈现时创建回调并将其传递给子组件,则该子组件的支持将发生更改。但是,当父组件呈现时,常规组件将重发(到虚拟区域),甚至道具也保持不变。例外是实现classComponent的shouldComponentUpdate,并比较道具(如PureComponent)。
这是一个优化,您应该只关心它,如果重命名子组件需要大量的计算(如果您将它多次呈现到同一个屏幕,或者它将需要一个深的或重要的改进机)。
如果是这样的话,您应该确保:
使用回忆录自定义设置器
虽然我不建议为特定组件构建一个独特的回忆录设置器(您需要注意一些事情),但是您可以使用一个通用钩子来负责实现。
下面是一个useObjState钩子的例子,它提供了一个简单的API,并且不会导致额外的重发器。
const useObjState = initialObj => {
const [obj, setObj] = React.useState(initialObj);
const memoizedSetObj = React.useMemo(() => {
const helper = {};
Object.keys(initialObj).forEach(key => {
helper[key] = newVal =>
setObj(prevObj => ({ ...prevObj, [key]: newVal }));
});
return helper;
}, []);
return [obj, memoizedSetObj];
};
function App() {
const [user, memoizedSetUser] = useObjState({
id: 1,
name: "ed",
age: null,
});
return (
<NameComp
setter={memoizedSetUser.name}
name={user.name}
/>
);
}
const NameComp = ({name, setter}) => (
<div>
<h1>{name}</h1>
<input
value={name}
onChange={e => setter(e.target.value)}
/>
</div>
)发布于 2022-10-03 06:53:30
useReducer和useState -的实用观察
UseState:
在我的React中,我有一个屏幕,其中包含使用25+创建的不同状态。
我在useEffect (componentDidMount)中调用一个api,在获得基于某些条件的响应时,我将设置这25个状态,为每个函数调用25个状态设置函数。
我已经放置了一个重呈现计数器并检查了,我的屏幕是重新呈现的 times.。
同样地,重呈现计数:
let count = 0;
export default function Home(props) {
count++;
console.log({count});
//...
// Rest of the code
}UseReducer :
然后,我在useReducer状态中移动了这25种状态,并且只使用一个操作来更新这些状态。
我观察到只有2次重呈现.
//API calling method:
fetchData()
{
const response = await AuthAxios.getHomeData();
dispatch({type: 'SET_HOME_DATA', data: response.data});
}
//useReducer Code:
const initialStaes = {
state1: null,
state2: null,
//.....More States
state27: null,
state28: null
}
const HomeReducer = (state, action) => {
switch (action.type) {
case 'SET_HOME_DATA': {
return {
...state,
state1: (Data based on conditions),
state2: !(some Conditions ),
//....More states
state27: false
}
}
}
}本例中useReducer的useReducer优势:
https://stackoverflow.com/questions/54646553
复制相似问题