在反应上下文中传递多个状态

时间:2021-07-02 07:34:18

标签: reactjs typescript react-context

我有一个上下文应该在树中传递多个状态。 设置 Provider 值的正确方法是什么?

  1. 就地创建对象不起作用,因为它在每次重新渲染时都会重新构建,如果上下文的实际内容没有改变(因为一个新对象),也会导致子级重新渲染被创建,使用不同的内存地址,导致孩子认为对象改变了)。

我应该如何传递上下文?

//Example:
interface Context {
 state1: number,
 state2: number,
}

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

 return(
   <MyContext.Provider value={????}>
      {/* components */}
   <MyContext>
 )
}

2 个答案:

答案 0 :(得分:1)

您可以将键控数组传递给值:

value={{'state1':[state1,setstate1],'state2':[state2,setstate2]}}

然后你可以检索每个数据:

const context = React.useContext(MyContext);
const [state1,setstate1] = context['state1'];
const [state2,setstate2] = context['state2'];

或者直接:

const [state1,setstate1] = React.useContext(MyContext)['state1'];
const [state2,setstate2] = React.useContext(MyContext)['state2'];

您可以添加所需的州数。

答案 1 :(得分:1)

在上下文中传递复杂状态的选项有多种。

选项 1:拆分不会一起更改的上下文

如果组成上下文的元素不是紧密相关的,请考虑将上下文拆分为不同的上下文。这样你就可以传递单个状态,而不必处理“统一”状态的问题。

方案二:使用useReducer组合相关状态

<块引用>

当使用 useState hook 时,建议为 每个元素,因为与类组件中的状态不同,更新 状态的单个元素可能会导致不必要的复杂性。

使用状态是功能组件中保存状态最常用的工具。

然而,当需要更复杂的状态(和状态管理)时,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

当前面的选项都不可行时, 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 prop 内放置一个内联对象。正如文章开头所说,这个对象在每次渲染时重新创建(新的内存地址),导致检查它的钩子重新渲染(因为观察到的内存值改变了)以及在小部件树中。< /p>

在这种情况下使用备忘录可能会变得很少,因为它可以避免传递内联对象:

//Example for useReducer. Works also with useState.

const contextValue = useMemo(() => {
  return { state, dispatch };
}, [state, dispatch]);

来源: