反应上下文;子组件未重新呈现

时间:2020-08-28 09:39:16

标签: javascript reactjs react-context react-functional-component

我可能会误解反应上下文通常如何工作,但我认为应该如何工作

我有一个主应用程序,具有如下的Context提供程序

export default function app(){
   return <contextObj.Provider value={Complex Object with multiple properties...}>
     <Main/>
   </contextObj.Provider>
}

我的主要应用程序如下

export default function main(){
   //Have imported the context class and am using it
   let store = React.useContext(myContext)
   
   return <React.Fragment> 
     <comp1 max={store.valueX} />
     <comp2 />
   </React.Fragment>
}

在comp2内部,修改上下文objext内部的valueX

export default function comp2(){
   //Have imported the context class and am using it
   let store = React.useContext(myContext)

   return <buttonComp onClick={()=>store.valueX=3} />
}

所以从理论上说comp1应该接收更新后的值并重新渲染? 这就是我所坚持的,因为更改context属性不会导致comp1重新呈现。

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:2)

就像正常的组件状态一样,您不能仅直接更改(分配)上下文的值。您需要将值包含在state中,并传递回调以更改该状态(或使用useDispatch):

export default function App() {
  const [value, setValue] = useState({
    /* Complex Object with multiple properties */
  });

  const updateX = (newX) =>
    setValue((prevValue) => {
      return { ...prevValue, valueX: newX };
    });

  return (
    <contextObj.Provider value={{ ...value, updateX }}>
      <Main />
    </contextObj.Provider>
  );
}

export default function Comp2() {
  //Have imported the context class and am using it
  let store = React.useContext(myContext);

  return (
    <ButtonComp
      onClick={() => {
        store.updateX(3);
      }}
    />
  );
}

您可能需要将状态和回调移动到为此专门制作的组件中-例如MyContextProvider仅包含状态并将其子级包装在MyContext.Provider中。

export function MyContextProvider({ initialValue, children }) {
  const [value, setValue] = useState(initialValue);

  const updateX = (newX) =>
    setValue((prevValue) => {
      return { ...prevValue, valueX: newX };
    });

  return (
    <MyContext.Provider value={{ ...value, updateX }}>
      {children}
    </MyContext.Provider>
  );
}

export default function App() {
  return (
    <MyContextProvider
      initialValue={/* Complex object with multiple properties */}
    >
      <Main />
    </MyContextProvider>
  );
}

但是,如果要在App内派生具有多个属性的复杂对象,则像在我的第一个示例中那样直接使用Context.Provider可能会更容易。

此外,请记住始终capitalize your components' names

注意:始终以大写字母开头组件名称

React将以小写字母开头的组件视为DOM标签。 例如,<div />代表HTML div标签,而<Welcome /> 表示一个组件,并且要求Welcome在范围内。

要了解有关此约定背后原因的更多信息,请阅读 JSX In Depth

答案 1 :(得分:1)

您不应直接在子级内部更改上下文。

相反,您应该调用一个函数/ reducer来改变上下文。

现在正在发生什么,您正在修改对象“存储”(该对象是您的上下文)中的一个值“ valueX”。为了做出反应,该对象仍然生活在相同的内存位置,因此未检测到更改。

cbr已经正确回答了您应该做什么。