使用 useContext
的基本概念
useContext
是 React Hooks 的一部分,用于在函数组件中访问 React 的 Context。Context 提供了一种在组件树中共享数据的方式,避免了逐层传递 props 的繁琐。
创建 Context
需要先通过 React.createContext
创建一个 Context 对象,并设置默认值(可选):
javascript
const MyContext = React.createContext(defaultValue);
提供 Context 值
在父组件中使用 Context.Provider
包裹子组件,并通过 value
属性传递数据:
javascript
<MyContext.Provider value={/* 共享的数据 */}>
<ChildComponent />
</MyContext.Provider>
在子组件中消费 Context
在函数组件中通过 useContext
直接获取 Context 的值:
javascript
const value = useContext(MyContext);
小栗子
以下是一个完整的示例,展示如何创建、提供和使用 Context:
ts
import React, {useState, useContext} from 'react'
interface ThemeContextType {
theme: string
setTheme: (theme: string) => void
}
// 声明上下文
const MyContext = React.createContext<ThemeContextType>({} as ThemeContextType)
const style = {
width: '100px',
height: '100px',
backgroundColor: 'black',
marginTop: '10px'
}
const Child = () => {
const theme = useContext(MyContext)
return (
<div>
子组件
<button onClick={() => theme.setTheme('dark')}>子组件切换</button>
<div style={{...style, backgroundColor: theme.theme == 'light'? 'green': 'black'}}>
</div>
</div>
)
}
const Parent = () => {
// 使用上下文
const theme = useContext(MyContext)
return (
<div>
父组件
<button onClick={() => theme.setTheme('light')}>父组件切换</button>
<div style={{...style, backgroundColor: theme.theme == 'light'? 'green': 'black'}}></div>
<Child />
</div>
)
}
export const App = () => {
const [theme, setTheme] = useState('light')
return (
<div>
<button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>主题切换</button>
<MyContext.Provider value={{theme, setTheme}}>
<Parent />
</MyContext.Provider>
</div>
)
}
export default App
注意:上面的栗子是React18的语法,React19中已经不需要使用Provider。
ts
// React 19的语法
<MyContextvalue={{theme, setTheme}}>
<Parent />
</MyContext>
多 Context 使用
一个组件可以消费多个 Context,只需多次调用 useContext
:
javascript
const user = useContext(UserContext);
const theme = useContext(ThemeContext);
性能优化
避免因不必要的重新渲染导致性能问题,可以将 Context 的值通过 useMemo
或 useState
进行优化:
javascript
const [value, setValue] = useState(initialValue);
const memoizedValue = useMemo(() => ({ value, setValue }), [value]);
return (
<MyContext.Provider value={memoizedValue}>
{/* 子组件 */}
</MyContext.Provider>
);
注意事项
- 默认情况下,
useContext
会监听 Context 值的变化,即使父组件使用React.memo
或shouldComponentUpdate
,子组件仍会重新渲染。 - 如果 Context 的
value
是一个新对象(如value={``{ theme }}
),每次渲染都会触发子组件更新,应避免直接传递内联对象。 - 如果重复嵌套使用并且使用的值是相同的则里层的值会覆盖外层的值。