我想了解在组件中使用
useContext
时 React 的行为方式。
假设我有一个名为
appContext
的顶级上下文,它有一个像 这样的嵌套对象结构
{ key1: value1, key2: { child: childValue }}
一个名为
ChildComp
的组件正在使用它,如下所示:
const appState = useContext(appContext); const someValue = appState.key2.child;
在这种情况下,只有
ChildComp
发生变化时,childValue
才会重新渲染?
如果将
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>