ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【React 系列 02】❤️ Custom Hooks 中使用 React Context

2021-10-04 20:33:42  阅读:182  来源: 互联网

标签:02 context GlobalContext Hooks React useContext Context 组件 Consumer


在上一篇 对于 Custom React Hooks 一些思考 文章末尾提及了 React Context,那么在本篇中我们将了解一下 React Context 怎么解决状态共享问题以及一些其它想法。

关于 React Context

提供 官网对于 usecontext 的介绍

const value = useContext(MyContext);

无论组件在组件树中的深度如何,React Context 都为组件提供数据。 上下文用于管理全局数据,例如 全局状态、主题、服务、用户设置等。

那么我们回到上篇文章提及到的例子吧,如何在父子组件中共享 useBoolean 返回的状态呢?

怎样使用 Context

在给出一份解决方案前,先来说明一下如何使用 Context。步骤也是比较简单:

  • creating the context
  • providing the context
  • consuming the context

creating the context

首先在 src 目录下创建一个名为 context 的文件夹,创建 index.tsx 文件

通过 createContext 来进行创建操作

import { createContext } from 'react';

const GlobalContext = createContext({})

export default GlobalContext;

providing the context

接下来,在父组件中 providing the context,并且将之前编写的 Custom Hooks(useBoolean)返回的 state 作为 value 值提供给子组件。

import SubApp from './subApp';
import useBoolean from './custom-hooks/useBoolean/index';
import GlobalContext from './context/index'

function App() {
  const [state, { toggle, setTrue, setFalse }] = useBoolean(true);

  return (
    <div>
      <p>Effects:{JSON.stringify(state)}</p>
      <p>
        <button type="button" onClick={() => toggle()}>
          Toggle
        </button>
        <button type="button" onClick={setFalse} style={{ margin: '0 16px' }}>
          Set false
        </button>
        <button type="button" onClick={setTrue}>
          Set true
        </button>
      </p>
      // providing the context
      <GlobalContext.Provider value={state}><SubApp /></GlobalContext.Provider>
    </div>
  )
}

export default App;

consuming the context

作为消费方法其实有两种,一种是通过 useContext(Context),另外一种是通过 Context.Consumer 提供一个特殊组件的渲染函数。

通过 useContext(Context)

子组件代码编写如下:

import { useContext } from 'react'
import GlobalContext from './context/index'

const SubApp = () => {
  // useContext
  const val = useContext(GlobalContext)
  return (
    <div>
      <p>subEffects:{JSON.stringify(val)}</p>
    </div>
  )
}
export default SubApp

看起来这种实现方式也是比较简单的,我们看看效果,当我们点击 Toggle 按钮时,发现在父子状态进行了共享,效果实现。

通过 Context.Consumer

接下里,试一下第二种方式,代码如下:

import GlobalContext from './context/index'

const SubApp = () => {
  return (
    <div>
      <GlobalContext.Consumer>
        {(val) => <p>subEffects:{JSON.stringify(val)}</p>}
      </GlobalContext.Consumer>
    </div>
  )
}
export default SubApp

进行相同的操作,也同样实现了效果。

拓展知识

经过上述两个方法的实现,基本上也解决了上篇文章提及的问题。在这里补充一下关于 context 的知识。

对于我们创建的 context,就比如上文我创建的 GlobalContext,它可以拥有任意数量的Consumer。

如果 GlobalContext 值发生变化(通过更改 Context.Provider 的 value 属性 ),那么所有的 Consumer 都会立即收到通知并重新渲染。

可能文字的表述不是很清楚,那么就以下列图示来说明(图画的有点简单,凑合下吧 hh)


假设组件 APP 是我们的 Provider,底下组件 ABCE 都是它的 Consumer,那么当我更改 Context.Provider 的 value 属性时,所有的 Consumer(这里指 ABCE)都会收到通知并重新渲染。

细心的小伙伴可能发现了,不还有个组件 D 没说嘛,下面就来说明:

如果 Consumer 没有被包装在 Context.Provider 中,但仍然尝试访问 Context (使用 useContext(Context) 或 <Context.Consumer>),那么 Context 值拿到的是 createContext(defaultValue) 的默认值 。

const GlobalContext = createContext({})

如上述代码,就比如之前创建的 GlobalContext,子组件如果被包装在 GlobalContext.Provider 中,那么获取的就是更改的 value 值,而如果没有被包的话,就是获取的默认值(这里是 {})

Context 该何时何地使用

在上文,我们了解了 Context 使用好处,但我们应该在哪个场景去使用它呢?难道不成就随便用就好了?会给我们带来什么问题呢?

我们一步一步来回答上述问题。

首先是我们应该在哪个场景去使用它呢?

一提到共享状态以及本文中创建的也是 GlobalContext,就想到全局状态了。

我们可以存放一些全局状态,比如一些用户基本信息,应用的一些配置项(比如认证,基本信息等),以及服务相关等等,这个就可以根据具体的业务需求来决定了。

但是,在我们使用 Context 不得不考虑一下该怎样使用它,难道真就随便用?

就以本文的代码例子来说,我们通过了两种方式在父子组件中实现状态的共享,但是发现没有,只要包括在 GlobalContext.Provider 其中的子组件,都必须使用 useContext(Context) 和 Context.Consumer 或者其它可能的方式来实现。

如果子组件很多,那这样层层环扣,岂不是影响的层级会比较多,而且在子组件中就会多增加一行代码,整个树结构复杂性就会上升。

当然,如果子树必须共享状态或者组件内有大量的计算,那么使用 Context 还是会方便许多,它可以减少一些没必要的计算,直接共享就完事了。

结尾

那么,本文到此就结束了,你会期待接下来的文章吗?

我是【一百个Chocolate】,希望在文章中体现自己的思考,然后与大家分享,坚持学习打卡第二篇,我们下期再见。

标签:02,context,GlobalContext,Hooks,React,useContext,Context,组件,Consumer
来源: https://blog.csdn.net/weixin_42429718/article/details/120602680

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有