在上下文中传递复杂状态的选项有多种。
选项 1:拆分不会一起改变的上下文
如果构成上下文的元素不紧密相关,请考虑将上下文拆分为不同的上下文。通过这种方式,您可以传递单个状态,而无需处理“统一”状态的问题。
方案二:使用useReducer组合相关状态
当使用 useState 钩子时,建议为
每个元素,因为,与类组件中的状态不同,更新
状态的单个元素可能会导致不必要的复杂性。
使用状态是功能组件中保存状态最常用的工具。
但是,当需要更复杂的状态(和状态管理)时,可以使用 useReducer 将状态包装在单个对象中。然后你可以将 reducer 的状态作为上下文的值传递
function reducer(state,action) {
switch(action.type){
//Cases:
//.... (works like redux reducer)
default:
return state
}
}
const MyContext = React.createContext<Context|null>(null)
const MyFC: React.FC = (props)=>{
const [compressedState,dispatch] = useReducer(reducer,{state1:0,state2:0})
const [state3,setState3] = useState<number>(0) //Not to pass down
return(
<MyContext.Provider value={compressedState}>
{/* components */}
<MyContext>
)
}
选项 3:使用备忘录
当前面的选项都不可行时,useMemo 是要走的路。
只需将需要传递的所有元素组合起来,即可创建一个仅在至少有一个依赖项发生更改时才更新的值。
const MyContext = React.createContext<Context|null>(null)
const MyFC: React.FC = (props)=>{
const [state1,setState1] = useState<number>(0) //To pass down
const [state2,setState2] = useState<number>(0) //To pass down
const [state3,setState3] = useState<number>(0) //Not to pass down
const contextValue= useMemo(()=>{
return{
state1: state1,
state2: state2
}
},[state1,state2]);
return(
<MyContext.Provider value={contextValue}>
{/* components */}
<MyContext>
)
}
关于 useMemo 的最后说明
当我们需要同时传递 useState(状态和设置状态)或 useReducer(状态和调度)的两个元素时,使用备忘录也会变得有用。
在上下文中,我们应该始终避免在 value 属性内放置一个内联对象。正如文章开头所说,这个对象在每次渲染(新内存地址)时重新创建,导致检查它的钩子重新渲染(因为观察到的内存值发生了变化)以及在小部件树中。
在这种情况下使用备忘录可能会变得很少,因为它可以避免传递内联对象:
//Example for useReducer. Works also with useState.
const contextValue = useMemo(() => {
return { state, dispatch };
}, [state, dispatch]);
来源: