学习ReactJS Context: 深入理解和使用useContext
不管是在 Vue
还是在 React
中,都是通过 Props
向数据传递到子组件中,如果组件嵌套很深,就会有 Props
透传的问题。
在 Vue
中提供了 provide
和 inject
依赖注入的方式来解决,这样只需要在父组件通过 provide
提供数据,然后在任何深层的嵌套的子组件中都可以通过 inject
获取到父组件提供的数据,而且只要父组件提供的数据有变化,那么只要通过 inject
中访问数据的组件都会获取到最新的数据。
在 React
中也提供了对应的解决方式: Context
也可以将数据传递到任意深层嵌套的组件中。使用 Context
可以用来管理全局数据、主题、用户设置等全局状态信息,可以自己封装一个简易的 store
来管理全局的状态。在 React
中使用 Context
需要3个步骤:1. 创建 Context
2. 通过 context provider
提供数据,3. 在子组件中可以通过 Consumer
和 useContext hook
访问父组件提供的数据。
创建 Context
在组件外,使用 React
中内置的方法 createContext(default)
创建 Context
的实例。 createContext
的参数是 defaultValue
可以提供一个默认值。createContext
返回一个 Context
实例。
context.js
import { createContext } from 'react';
const Context = createContext(default value);
Provider
数据
把需要数据的组件用 Context.Provider
包括起来,并通过 value
属性提供数据。只有嵌套在 Context.Provider
中的组件才能够访问到提供的数据。
import Context from './context';
function Main() {
const value = 'My Context Value'; // 可以使任意的js类型
return (
<Context.Provider value={value}>
<MyComponent />
</Context.Provider>
);
}
不同的 Context
可以嵌套使用
import { ThemeContext, AuthContext } from './context.js'
export const App = () => {
return (
<ThemeContext.Provider value={theme}>
<AuthContext.Provider value={user}>
<MyComponent />
</AuthContext.Provider>
</ThemeContext.Provider>
)
}
同一个 Context
之间也可以相互嵌套,这是嵌套在内层的 Context
提供的数据会覆盖上层的数据
import { ThemeContext } from './context.js'
export const App = () => {
return (
<ThemeContext.Provider value='dark'>
<ThemeContext.Provider value='light'>
<MyComponent />
</ThemeContext.Provider>
</ThemeContext.Provider>
)
}
最终在 MyComponent
中获取的数据会是 light
封装 Provider
import { ThemeContext } from './context.js'
const Provider = ({ children }) => {
const theme = 'light'
return (
<ThemeContext.Provider value={theme}>
{ children }
</ThemeContext.Provider>
)
}
使用
<Provider>
<MyComponent />
</Provider>
在子组件中获取数据
- 使用
Context.Consumer
,
import { ThemeContext } from './context.js'
// 这种方式在新版本中已不推荐使用
<ThemeContext.Consumer>
{theme => (
<button className={theme} />
)}
</ThemeContext.Consumer>
- 使用
hook
-useContext
import { ThemeContext } from './context.js'
// 推荐使用 hook 方式
function Button() {
const theme = useContext(ThemeContext);
return <button className={theme} />;
}
优化重复渲染
你可以在 value
传递任何类型的数据,当传递的是 object
function
时,父组件每一次渲染,就会导致所有调用 useContext
的子组件都会重新渲染一次
function MyApp() {
const [currentUser, setCurrentUser] = useState(null);
function login(response) {
storeCredentials(response.credentials);
setCurrentUser(response.user);
}
return (
<AuthContext.Provider value={{ currentUser, login }}>
<Page />
</AuthContext.Provider>
);
}
优化的思路就是使用 useCallback
优化方法
const login = useCallback((response) => {
storeCredentials(response.credentials);
setCurrentUser(response.user);
}, []);
使用 useMemo
优化对象,优化后
const contextValue = useMemo(() => ({
currentUser,
login
}), [currentUser, login]);
整体代码
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>
);
}
这样优化之后,所有调用 useContext(AuthContext)
的子组件,不会再重复渲染,除非 currentUser
的值发生变化
相关主题
通过Vue3对比学习Reactjs: 模板语法 vs JSX Vue vs Reactjs之 props Vuejs vs Reactjs:组件之间如何通信 解密v-model:揭示Vue.js和React.js中实现双向数据绑定的不同策略 从零开始:如何在Vue.js和React.js中使用slot实现自定义内容
转载自:https://juejin.cn/post/7250669238418538553