【问题标题】:React context; child component not rerendering反应上下文;子组件不重新渲染
【发布时间】:2020-12-17 05:42:37
【问题描述】:

我可能误解了 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 重新渲染。

【问题讨论】:

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


    【解决方案1】:

    就像正常的组件状态一样,您不能直接改变(分配给)上下文的值。您需要将值包含在 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 标签。 例如,&lt;div /&gt; 表示 HTML div 标签,但 &lt;Welcome /&gt; 表示一个组件并要求Welcome 在范围内。

    要详细了解此约定背后的原因,请阅读 JSX In Depth.

    【讨论】:

    • 谢谢你的解释,我会试试这个,如果有效,我会在适当的时候更新!我对此比较陌生,所以请耐心等待!
    【解决方案2】:

    你不应该直接改变孩子内部的上下文。

    你应该调用一个函数/reducer 来改变上下文。

    现在发生了什么,您正在修改一个值,即对象“存储”中的“valueX”(该对象是您的上下文)。对于 react 对象仍然存在于相同的内存位置,所以没有检测到变化。

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

    【讨论】:

    • 谢谢你的解释,我会试试这个,如果有效,我会在适当的时候更新!我对此比较陌生,所以请耐心等待!
    猜你喜欢
    • 2021-01-29
    • 2020-03-08
    • 2019-11-23
    • 1970-01-01
    • 1970-01-01
    • 2018-12-27
    • 2018-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多