精读React hooks(三):useContext从基础应用到性能优化
上一篇文章(全面掌握useReducer)我们用useReducer
和useContext
实现了一个切换主题的功能,useReducer
我们已经掌握了,那么本文就来学习useContext
。
我们知道,每一个hook
的诞生都有它独特的使命,比如useState
是解决组件内状态更新的问题,useReducer
是解决组件复杂状态更新的问题。
而useContext
要解决的是:让开发者在某些场景下,从多层嵌套传值的组件树中解脱出来;useContext
实现的是:让开发者通过context
实现跨层级共享状态。
基础用法
- 创建 Context
首先,我们需要使用React.createContext
创建一个context
对象:
这里的defaultValue
是当组件不在任何 Context Provider 内部时的默认值,defaultValue
可以用 null,但 React 官方建议提供一个有意义的默认值,这样可以让调用usecontext
组件更安全。
- 使用 Context Provider
为了在组件树中使用这个context
,我们需要使用<MyContext.Provider>
组件,它接受一个value
prop,这就是你想在它的子组件中共享的值。
- 在组件中访问 Context
在函数组件中,可以使用useContext
hook 来访问这个 context 的值。
这里的contextValue
就是第二步传入的someValue
,而且contextValue
获取到的永远是最新的值。
一个示例
我们来看一个更直观的示例:
这个示例中,App 中引用了ThemeContext
并传了值,ThemeButton 是 App 的孙组件,这二者之间没有通过 Toolbar 进行嵌套传值,但是 ThemeButton 依然通过useContext
拿到了 App 里的值。
从这个示例中我们可以总结出,React.createContext
和useContext
共同组成了一个管道,通过这个管道,开发者可以进行跨组件共享状态。
进阶技巧
动态Context值
有的时候 Context 传的值需要动态变化,我们可以基于useState去更新状态,更新后的值会实时反应到调用 Context 的组件上。
如果要更新对象也是可以的:
和useReducer共用
在大型应用中,通常会将useContext
与useReducer
结合起来使用,以便从组件中提取与某些状态相关的逻辑。上一篇文章即是用这种思路实现了主题切换,源码可查看Github:useReducer-useContext实现主题切换,本文不再重复。
覆盖Provider value
当我们调用多个相同 Context,会实现value
的覆盖
高级应用——性能优化
当我们在使用useContext
时,一个经常被提到的问题是性能优化。如果不正确地使用,Context 可能导致不必要的组件渲染,从而影响应用性能。
为什么会出现性能问题?
当Provider
的value
属性值发生变化时,所有使用了useContext
的组件都将重新渲染。如果value
经常变化,或者消费者组件很多,那么这会引起大量的不必要的渲染。
怎样解决?
-
粒度化 Context
如果你的 context 包含许多不同的状态值,尝试将它们分解成更小的 context。例如,而不是只有一个大的 AppContext,你可以有 UserContext、ThemeContext 等。这样,当某一部分的数据发生变化时,只有依赖于那部分数据的组件会重新渲染。
-
使用多个 Context 提供者
这与上一点相似。你可以为应用中的不同部分使用不同的 context 提供者,确保仅当真正需要的数据更改时才重新渲染组件。
-
使用useMemo
和useCallback
优化value
为了避免value
变化造成子孙组件频繁的重新渲染,可以使用useMemo
和useCallback
对参数和方法进行缓存,减少value
的无意义更新。
注:如果你的应用状态经常发生变化,并触发大量组件的更新,那么这种情况不适合用useContext
,请立即考虑其它状态更新方案。
结语
希望本文所讲的useContext应用和技巧能帮助你掌握useContext
hook。
专栏资源
专栏博客地址:精读React Hooks
专栏演示站:React Hooks Demos
专栏源码仓库:👉Github - Source Code
交个朋友:👉加入「独立全栈交流群」
专栏文章列表:
精读React hooks(一):useState 的几个基础用法和进阶技巧
精读React hooks(二):React状态管理的强大工具——useReducer
精读React hooks(三):useContext从基础应用到性能优化
精读React hooks(四):useRef的多维用途
精读React hooks(五):useEffect使用细节知多少?
精读React hooks(六):useLayoutEffect解决了什么问题?
精读React hooks(七):用useMemo来减少性能开销
精读React hooks(八):我们为什么需要useCallback
精读React hooks(九):使用useTransition进行非阻塞渲染
精读React hooks(十):使用useDeferredValue延迟状态更新
精读React hooks(十一):useInsertionEffect——CSS-in-JS样式注入新方式
精读React hooks(十二):使用useImperativeHandle能获得什么能力
精读React hooks(十三):使用useSyncExternalStore获取实时数据
精读React hooks(十四):总有一天你会需要useId为你生成唯一id
精读React hooks(十五):把useDebugValue加入你的React调试工具库
精读React hooks(十六):一个为代码优雅而生的hook——use