深层嵌套状态更改的 UseContext 行为

问题描述 投票:0回答:1

我想了解在组件中使用

useContext
时 React 的行为方式。

假设我有一个名为

appContext
的顶级上下文,它有一个像

这样的嵌套对象结构

{ key1: value1, key2: { child: childValue }}

一个名为

ChildComp
的组件正在使用它,如下所示:

const appState = useContext(appContext); const someValue = appState.key2.child;

在这种情况下,只有

ChildComp
发生变化时,
childValue
才会重新渲染?

reactjs react-hooks
1个回答
0
投票

如果将

context
值放入
state
中,则子组件将重新渲染:

const { useState, useCallback, createContext, useContext } = React;

const AppContext = createContext(null);

const ChildComp = () => {
  console.log('Child rendered');
  
  const appState = useContext(AppContext);
  const someValue = appState.key2.child;
  
  return <div>Value: {someValue}</div>;
}

const App = () => {
  const [value, setValue] = useState({ key1: 1, key2: { child: 2 }});
  
  const clickHandler = useCallback(() => {
    setValue(prev => {
      const updated = structuredClone(prev);
      
      ++updated.key2.child;
      
      return updated;
    })
  }, []);
  
  return (
    <AppContext.Provider value={value}>
      <button onClick={clickHandler}>Update nested value</button>
      <ChildComp />
    </AppContext.Provider>
  );
}

// Render

const container = document.querySelector('#root');

if (container === null) throw new Error('Root component doesn\'t exist');

ReactDOM.createRoot(container).render(<App />);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>

<div id="root"></div>

如果将

context
值放入某个全局变量中,则子组件将不会重新渲染:

const { useState, useCallback, createContext, useContext } = React;

let contextValue = { key1: 1, key2: { child: 2 }};
const AppContext = createContext(contextValue);

const ChildComp = () => {
  console.log('Child rendered');
  
  const appState = useContext(AppContext);
  const someValue = appState.key2.child;
  
  return <div>Value: {someValue}</div>;
}

const clickHandler = () => {
  contextValue = structuredClone(contextValue);
  
  ++contextValue.key2.child;
  
  console.log(contextValue);
}

const App = () => {
  return (
    <AppContext.Provider value={contextValue}>
      <button onClick={clickHandler}>Update nested value</button>
      <ChildComp />
    </AppContext.Provider>
  );
}

// Render

const container = document.querySelector('#root');

if (container === null) throw new Error('Root component doesn\'t exist');

ReactDOM.createRoot(container).render(<App />);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>

<div id="root"></div>

© www.soinside.com 2019 - 2024. All rights reserved.