React - Context 解决深层参数传递问题

前言

在一个参数需要传递非常多层 props 的时候,我们就需要考虑将其优化。

假设说 A 父组件获取到了一个参数 a,并且页面的嵌套状态为 A->B->C->D->E 只有 E 这个子组件需要参数 a,那么要是通过 props 的话,B C D 三个组件就也需要接收这个参数,并且完全没有使用,都只是向下传递。

这样就会造成很多不必要的歧义,假设在之后移除了组件 E,那么这么多的props需不需要删掉?删掉的话又是大工程,你需要确保这个参数在这些组件里面都已经无用了。总之这种做法会给开发带来很多的麻烦。

这个的解决方法可能挺多,可以通过透传,数据仓库,事件发布等等解决,具体需要看业务需求,那么让我们看看另外一种场景,在一个区域当中,有一个参数是很多组件通用的,比方说

js 复制代码
<Section>  
	<Heading level={3}>关于</Heading>  
	<Heading level={3}>照片</Heading>  
	<Heading level={3}>视频</Heading>  
</Section>

通用的level参数可能你需要重复写3次,并且要是需要的组件个数增多,就可能需要更多次,这些都属于重复代码。

今天就来介绍一下解决上面两个问题的一个方案 透传 context。

什么是 Context

context 是 传递 props 的另一种方法

Context provides a way to pass data through the component tree without having to pass props down manually at every level.

Context 提供了一种通过组件树传递数据的方法,而无需在每个级别手动传递 props

事实上官方设计这个 API 的目的是 共享可被视为React组件树的"全局"数据,例如当前经过身份验证的用户,主题或首选语言

意图言简意赅,我们都知道,React 组件是树状结构,我们可以在这个树状结构的某一个节点注入一个上下文对象,那么在这个节点下面的所有组件都能够使用这些数据。

Context 的用法

context 有两种使用方法,创建方法都是一样的,首先需要 React.createContext 这个方法来创建一个 context

并且这个对象上存在两个 API,分别是 ProviderConsumer

其中,Provider 是用来向组件树发出 context 对象,而 Consumer 是用来使用 Context 对象,要使用 Context 对象还有另外一种方法:使用 React.useContext 钩子,下面用两个例子来看一下两种使用方法。

首先我们可以在一个单独的文件创建我们的 context,因为 context 并不一定要和某个组件耦合,他可能可以用于任何地方,所以我们可以单独创建,之后在进行引入

js 复制代码
// LevelContext.js
import { createContext } from 'react';
  
export const LevelContext = createContext(1);

创建完了以后,我们就在需要使用的地方引入这个上下文对象,通过刚刚说的 Provider 我们可以将这个对象共享给组件树下面的组件。

js 复制代码
import { LevelContext, Provider, Consumer } from './levelContext.js';

function Section ({ level, children }) {
  return (
    <section className="section">
      <LevelContext.Provider value={level}>
        {children}
      </LevelContext.Provider>
    </section>
  );
}

上面是通过 LevelContext.Provider 来调用 Provider,当然你也可以即将他们分开来,这是完全一样的。

上面的 Section 组件,会输入一个子组件,然后将 LevelContext 这个上下文共享给子组件,value 就是我们需要共享的上下文

  1. 使用 React.useContext

然后我们先来看看用 React.useContext 接收上下文对象的写法,

js 复制代码
<Section level={1}>
	<AAA></AAA>
	<AAA></AAA>
	<AAA></AAA>
</Section>
js 复制代码
import { useContext } from 'react';
import { LevelContext } from './levelContext.js';

function AAA ({ }) {
  const level = useContext(LevelContext);
  return (
    <div>child {level}</div>
  )
}

这就是通过 React.useContext 的调用方法,页面能够正常展示我们传入的 1 .

  1. 通过 Consumer 引入,为了跟上面的那种方法做出对比,我们可以在上面的 AAA 组件种在加入另一种引入方法
js 复制代码
import { useContext } from 'react';
import { LevelContext, Consumer } from './levelContext.js';

function AAA ({ }) {
  const level = useContext(LevelContext);
  return (
    <div>child {level}
      <Consumer>
        {
          (context) => <p>{context}</p>
        }
      </Consumer>
    </div>
  )
}

页面还是能够正常展示上下文,两种方法需要在不同的情况下根据具体需求调用

Context 的优缺点

上面我们说明了 Context 能用来解决什么问题,但是这并不是一一定的,比方说多层传递 props 未必就比 context 要差,多层传递能够使得组件的可读性更好,但是 context 可能会在复杂组件中变得无法维护,因为你不知道他从哪里来的。并且 context 有就近的特点,多个上下文只有最近的那个会生效。

所以我们一般会在项目的跟组件定义一次上下文 centext ,以便于在整个项目都可以非常方便的使用,一些状态管理库也是基于这种工作逻辑。

总结

本文简单介绍了 context 以及一些使用方法,具体的使用还需要看具体需求,但是可以考虑在某些场景下使用 context,可能会获得更好的开发体验,1. 全局信息,包括但不限于:主题,用户信息,等等可能在项目全局任何地方用到的数据,2. 状态管理,状态管理的本质也就是将状态管理仓库通过 context 设定为全局状态,任何组件都可以去引用,获取库中的数据,或者借用库的方法来改变状态。

相关推荐
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端
爱敲代码的小鱼8 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax