开篇
在 React 中提供了一种「数据管理」机制:React.context
,大家可能对它比较陌生,日常开发直接使用它的场景也并不多。
但提起 react-redux
通过 Provider
将 store
中的全局状态在顶层组件向下传递,大家都不陌生,它就是基于 React 所提供的 context 特性实现。
本文,将从概念、使用,再到原理分析,来理解 Context 在多级组件之间进行数据传递的机制。
一、概念
Context
提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
通常,数据是通过 props 属性自上而下(由父到子)进行传递,但这种做法对于某些类型的属性而言是极其繁琐的(例如:地区偏好,UI 主题),这些属性是应用程序中许多组件都需要的。
Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props。
设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。
二、使用
下面我们以 Hooks 函数组件为例,展开介绍 Context 的使用。
2.1、React.createContext
首先,我们需要创建一个 React Context
对象。
const Context = React.createContext(defaultValue);
当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中的 Context.Provider 中读取到当前的 context.value 值。
当组件所处的树中没有匹配到 Provider 时,其 defaultValue 参数才会生效。
2.2、Context.Provider
每个 Context 对象都会返回一个 Provider React 组件,它接收一个 value 属性,可将数据向下传递给消费组件。当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染。
注意,当 value 传递为一个复杂对象时,若想要更新,必须赋予 value 一个新的对象引用地址,直接修改对象属性不会触发消费组件的重渲染。
<Context.Provider value={/* 某个值,一般会传递对象 */}>
2.3、React.useContext
Context Provider
组件提供了向下传递的 value
数据,对于函数组件,可通过 useContext
API 拿到 Context value
。
const value = useContext(Context);
useContext
接收一个 context 对象(React.createContext 的返回值),返回该 context 的当前值。
当组件上层最近的 <Context.Provider> 更新时,当前组件会触发重渲染,并读取最新传递给 Context Provider 的 context value 值。
题外话:React.memo 只会针对 props 做优化,如果组件中 useContext 依赖的 context value 发生变化,组件依旧会进行重渲染。
2.4、Example
我们通过一个简单示例来熟悉上述 Context
的使用。
const Context = React.createContext(null);
const Child = () => {const value = React.useContext(Context);return (<div>theme: {value.theme}</div>)
}