useContext返回 调用组件上方最近的 SomeContext.Provider 的 value
如果没有这样的 provider 传递给 createContext 的 defaultValue。返回的值始终是最新的。
如果 context 发生变化,React 会自动重新渲染读取 context 的组件。
- <Context.Provider> 需要位于调用 useContext() 的组件 之上。
- 使用 memo 来跳过重新渲染并不妨碍子级接收到新的 context 值。
https://codepen.io/pen?\&editors=001
javascript
const { createRoot } = ReactDOM;
const ThemeContext = React.createContext('light');
// import { createContext, useContext } from 'react';
const { Button, Flex } = antd;
// 由于组件A被放置在了<ThemeContext.Provider value="dark">的范围内,
//它会成功地从上下文中获取到ThemeContext的值。因此,组件A不需要直接传递ThemeContext,并且不会因此而报错。
const A = () => {
const theme = React.useContext(ThemeContext);
return <div>123{theme}</div>
}
const App = () => (
<ThemeContext.Provider value="dark">
<Flex gap="small" wrap="wrap">
<Button type="primary">Primary Button</Button>
<Button>Default Button</Button>
<Button type="dashed">Dashed Butto1n</Button>
<Button type="text">Text Button</Button>
<Button type="link">Link Button</Button>
</Flex>
<A/>
</ThemeContext.Provider>
);
const ComponentDemo = App;
createRoot(mountNode).render(<ComponentDemo />);
可以传递对象(通过 context 可以传递任何值)
javascript
<CurrentUserContext.Provider
value={{
currentUser,
setCurrentUser
}}
>
<Form />
</CurrentUserContext.Provider>
可以把把 provider 抽离成组件
javascript
<MyProviders theme={theme} setTheme={setTheme}>
<WelcomePanel />
</MyProviders>
function MyProviders({ children, theme, setTheme }) {
const [currentUser, setCurrentUser] = useState(null);
return (
<ThemeContext.Provider value={theme}>
<CurrentUserContext.Provider
value={{
currentUser,
setCurrentUser
}}
>
{children}
</CurrentUserContext.Provider>
</ThemeContext.Provider>
);
}
可以同时存在多个content
javascript
<ThemeContext.Provider value={theme}>
<CurrentUserContext.Provider
value={{
currentUser,
setCurrentUser
}}
>
<WelcomePanel />
</CurrentUserContext.Provider>
</ThemeContext.Provider>
还可以和useReducer结合使用,在大型项目中
覆盖context
javascript
const ThemeContext = createContext(null);
export default function MyApp() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
)
}
function Form() {
return (
<Panel title="Welcome">
<Button>Sign up</Button>
<Button>Log in</Button>
<ThemeContext.Provider value="light">
<Footer />
</ThemeContext.Provider>
</Panel>
);
}
如果context value是有函数等多个成员时,可以通过useCallback和usememo来优化性能
javascript
import { useCallback, useMemo } from 'react';
function MyApp() {
const [currentUser, setCurrentUser] = useState(null);
const login = useCallback((response) => {
storeCredentials(response.credentials);
setCurrentUser(response.user);
}, []);
const contextValue = useMemo(() => ({
currentUser,
login
}), [currentUser, login]);
return (
<AuthContext.Provider value={contextValue}>
<Page />
</AuthContext.Provider>
);
}
// 根据以上改变,即使 MyApp 需要重新渲染,调用 useContext(AuthContext) 的组件也不需要重新渲染,
// 除非 currentUser 发生了变化。