反应上下文;子组件不重新渲染

React context; child component not rerendering

我可能误解了 React 上下文的一般工作方式,但我认为它应该如何工作:

我有一个主应用程序,其中包含如下上下文提供程序

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内部,修改context 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 应该接收更新后的值并重新渲染? 这就是我卡住的地方,因为改变上下文 属性 不会导致我的 comp1 重新渲染。

就像正常的组件状态一样,您不能直接改变(分配给)上下文的值。您需要在状态中包含该值并向下传递回调以更改该状态(或使用 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:

Note: Always start component names with a capital letter.

React treats components starting with lowercase letters as DOM tags. For example, <div /> represents an HTML div tag, but <Welcome /> represents a component and requires Welcome to be in scope.

To learn more about the reasoning behind this convention, please read JSX In Depth.

你不应该直接改变 children 中的上下文。

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

现在发生了什么,您正在修改一个值,object“存储”中的“valueX”(object 是您的上下文)。对于 React,object 仍然存在于相同的内存位置,因此未检测到任何变化。

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