Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >useContext更佳实践

useContext更佳实践

作者头像
公众号@魔术师卡颂
发布于 2020-08-26 02:03:19
发布于 2020-08-26 02:03:19
90700
代码可运行
举报
文章被收录于专栏:魔术师卡颂魔术师卡颂
运行总次数:0
代码可运行

有人说:构建React应用就像用积木搭房子,每个组件就是一块积木。

这么说的人可能忽视了state(状态)—— 不同于组件是以树的形式组合,我们经常会在不同层级的组件间公用同一个state

面对这种情况,有些同学选择引入状态管理库(比如Redux)。

事实上,React内置的contextAPI可以解决大部分状态传递问题。

本文接下来要讲的,就是如何更有效的使用context

错误前置

在我们的Demo中,有个context——CountContext

当其render时如果上层结构中不存在context provider为他提供context value,则在解构context value时会报错。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const CountContext = React.createContext();

function CountDisplay() {
 // 解构语法报错
  const {count} = React.useContext(CountContext);
  return <div>{count}</div>;
}

这是因为CountContext没有默认值,所以为undefined。将undefined当作对象解构时报错。

在有些场景下默认值是有意义的。但是大多数情况,context consumer需要context provider为他提供有用的context value

这意味着使用context的业务组件需要判断undefined,否则可能出现运行时错误。

为了解决这个问题,我们可以用自定义hook错误前置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// src/count-context.js
const CountContext = React.createContext();

function useCount() {
  const context = React.useContext(CountContext);
  
  if (context === undefined) {
    throw new Error('必须在CountProvider内使用useCount');
  }
  
  return context;
}

同时提供CountProvider

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// src/count-context.js

function CountProvider({children}) {
  const stateHook = React.useState();
  return (
    <CountContext.Provider value={stateHook}>
      {children}
    </CountStateContext.Provider>
  )
}

在需要CountContext的业务组件中,我们不再需要直接使用CountContext,而是引入useCountCountProvider

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// src/app.jsx

import {useCount, CountProvider} from './count-context.js'

function CountDisplay() {
  const [count] = useCount();
  return <div>{count}</div>;
}

function App() {
  return (
    <CountProvider>
      <CountDisplay />
    </CountProvider>
  )
}

如果在未包裹CountProvider的情况下单独使用useCount,会直接抛出错误,而不需要等到使用context时再报错。

这种将错误前置的方式能够帮我们更好的规避运行时错误

state与dispatch分离

CountProvider中,stateHook作为context value传递给context consuer

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function CountProvider({children}) {
  const stateHook = React.useState();
  // ...
}

其中state与改变state的方法(dispatch)同时存在于context value中。

有些时候,展示state的组件与触发state变化的组件不是同一个组件,比如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function App() {
  return (
    <CountProvider>
      <CountDisplay />
      <Counter />
    </CountProvider>
  )
}

其中CountDisplay用于展示state

Counter用于触发state变化。

由于statedispatch同时存在于context valuestate变化后CountDisplayCounter都会重新render

这对于只负责触发组件state变化的Counter来说是不必要的。

为此,我们可以将statedispatch分离。

修改CountProvider

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// src/count-context.js

const CountStateContext = React.createContext();
const CountDispatchContext = React.createContext();

function CountProvider({children}) {
  const [state, dispatch] = React.useState();
  return (
    <CountStateContext.Provider value={state}>
      <CountDispatchContext.Provider value={dispatch}>
        {children}
      </CountDispatchContext.Provider>  
    </CountStateContext.Provider>
  )
}

同时,useCount也拆分为useCountStateuseCountDispatch

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// src/count-context.js

function useCountState() {
  const context = React.useContext(CountStateContext);
  
  if (context === undefined) {
    throw new Error('必须在CountProvider内使用useCountState');
  }
  
  return context;
}

function useCountDispatch() {
  const context = React.useContext(CountDispatchContext);
  
  if (context === undefined) {
    throw new Error('必须在CountProvider内使用useCountDispatch');
  }
  
  return context;
}

CountDisplay中使用useCountState

Counter中使用useCountDispatch

这样,即使state变化,只有CountDisplayrenderCounter不会render

更灵活的拓展

事实上,将context分离为动态(state),静态(dispatch)两部分后可以拥有更灵活的拓展。

当需要更多state时,可以将CountProvideruseState替换为useReducer

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// src/count-context.js

function CountProvider({children}) {
  const [state, dispatch] = React.useReducer(countReducer);
  return (
    <CountStateContext.Provider value={state}>
      <CountDispatchContext.Provider value={dispatch}>
        {children}
      </CountDispatchContext.Provider>  
    </CountStateContext.Provider>
  )
}

当需要更多方法时,你也可以拓展CountDispatchContext

总结

通过这套context的“更”佳实践,审视下我们现有的业务,是不是很多时候并不需要额外的状态管理库呢?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-08-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 魔术师卡颂 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
useContext
Context是React提供的一种跨组件的通信方案,useContext与useReducer是在React 16.8之后提供的Hooks API,我们可以通过useContext与useReducer来完成全局状态管理例如Redux的轻量级替代方案。
WindRunnerMax
2022/09/29
9980
120. 精读《React Hooks 最佳实践》
React 16.8 于 2019.2 正式发布,这是一个能提升代码质量和开发效率的特性,笔者就抛砖引玉先列出一些实践点,希望得到大家进一步讨论。
黄子毅
2022/03/14
1.2K0
用动画和实战打开 React Hooks(三):useReducer 和 useContext
随着应用状态越来越复杂,我们迫切需要状态与数据流管理的解决方案。熟悉 React 开发的同学一定听说过 Redux,而在这篇文章中,我们将通过 useReducer + useContext 的组合实现一个简易版的 Redux。首先,我们将带你重新认识“老朋友”useState,并借此引出这篇文章的主角:Reducer 函数与 useReducer 钩子,并通过实战一步步带你理清数据流和状态管理的基本思想。
一只图雀
2020/05/08
1.5K0
使用 React Hooks + Context 打造一个类vuex语法的简单数据管理。
React Hooks 是目前社区非常火热的一个新的特性,vue 3.0也引入了hooks,这个特性 在 React16.8 版本正式发布。
ssh_晨曦时梦见兮
2020/04/10
9690
React Hooks 万字总结
每个 hook 都会有一个 next 指针,hook 对象之间以单向链表的形式相互串联, 同时也能发现 useState 底层依然是 useReducer 再看看更新阶段发生了什么
ConardLi
2021/04/23
9470
react源码之深度理解React.Context
在 React 中提供了一种「数据管理」机制:React.context,大家可能对它比较陌生,日常开发直接使用它的场景也并不多。
flyzz177
2022/12/05
1.2K0
我在大厂写React学到了什么?性能优化篇
我工作中的技术栈主要是 React + TypeScript,这篇文章我想总结一下如何在项目中运用 React 的一些技巧去进行性能优化,或者更好的代码组织。
winty
2020/11/13
1.3K0
我在大厂写React学到了什么?性能优化篇
createContext & useContext 上下文 跨组件透传与性能优化篇
createContext api 可以创建一个 React 的 上下文对象,如果使用了这个上下文对象中Provider组件,就可以拿到上下文中提供的数据或者其它信息。
吴佳
2022/09/26
1.9K0
问:你是如何进行react状态管理方案选择的?
前言:最近接触到一种新的(对我个人而言)状态管理方式,它没有采用现有的开源库,如redux、mobx等,也没有使用传统的useContext,而是用useState + useEffect写了一个发布订阅者模式进行状态管理,这一点对我来说感觉比较新奇,以前从没接触过这种写法,于是决定研究一下目前比较常用的状态管理方式。
beifeng1996
2022/10/10
3.6K0
130. 精读《unstated 与 unstated-next 源码》
unstated 是基于 Class Component 的数据流管理库,unstated-next 是针对 Function Component 的升级版,且特别优化了对 Hooks 的支持。
黄子毅
2022/03/14
1K0
React Hook
在传统的 class 中,会使用 componentDidMount 和 componentDidUpdate 获取数据。同时 componentDidMount 中也会处理一些其他的事务,例如事件监听,定时器等等。而后还需要在 componentWillUnmount 中取消。万一忘记其中某一个部分或者处理的时间过多,很可能导致一些可怕的bug。
踏浪
2020/01/17
1.9K0
手写ReactHook核心原理,再也不怕面试官问我ReactHook原理
调用useState会返回一个state变量,以及更新state变量的方法。useState的参数是state变量的初始值,初始值仅在初次渲染时有效。
JowayYoung
2021/02/03
4.4K1
手写ReactHook核心原理,再也不怕面试官问我ReactHook原理
React-Redux 100行代码简易版探究原理。(面试热点,React Hook + TypeScript实现)
各位使用react技术栈的小伙伴都不可避免的接触过redux + react-redux的这套组合,众所周知redux是一个非常精简的库,它和react是没有做任何结合的,甚至可以在vue项目中使用。
ssh_晨曦时梦见兮
2020/04/11
2.1K0
React-Redux 100行代码简易版探究原理。(面试热点,React Hook + TypeScript实现)
「前端架构」使用React进行应用程序状态管理
管理状态可以说是任何应用程序中最难的部分。这就是为什么有这么多的状态管理库可用,而且每天都有更多的库出现(甚至有些库是建立在其他库之上的。。。npm上有数百个“更简单的Redux”的摘要)。尽管状态管理是一个很难解决的问题,但我认为,使之如此困难的一个原因是我们经常过度设计解决问题的方法。
架构师研究会
2020/11/06
2.9K0
React useReducer 终极使用教程
useReducer 是在 react V 16.8 推出的钩子函数,从用法层面来说是可以代替useState。相信前期使用过 React 的前端同学,大都会经历从 class 语法向 hooks 用法的转变,react 的 hooks 编程给我们带来了丝滑的函数式编程体验,同时很多前端著名的文章也讲述了 hooks 带来的前端心智的转变,这里就不再着重强调,本文则是聚焦于 useReducer 这个钩子函数的原理和用法,笔者带领大家再一次深入认识 useReducer。
蒋川@卡拉云
2022/08/31
3.8K0
React useReducer 终极使用教程
React+TypeScript使用规范
一个采用 parameterName is Type的形式返回 boolean 值的函数,但 parameterName 必须是当前函数的参数名
用户4619307
2023/05/04
4.7K0
你要的react+ts最佳实践指南
本文根据日常开发实践,参考优秀文章、文档,来说说 TypeScript 是如何较优雅的融入 React 项目的。
xiaofeng123aa
2022/10/03
3.1K0
浅谈 Hooks
如果你很熟悉 vue 与 react ,兴许你也觉得 vue3.0 抄袭了react,这项react 在不久前发布的新技术,在 vue3.0 中被重新搬上了舞台。也使它重新活跃在了人们的视野中,我技术不深,与大家分享我的见解和猜测。
我不是费圆
2020/10/13
1.9K0
在爱 context 一次,并结合 useReducer 使用,这次有一点简单
在 React 中,props 能够帮助我们将数据层层往下传递。而 context 能够帮助我们将数据跨层级往下传递。
用户6901603
2023/12/20
2730
在爱 context 一次,并结合 useReducer 使用,这次有一点简单
React系列-自定义Hooks很简单
不明白Redux工作流的同学可以看看这篇Redux系列之分析中间件原理(附经验分享)
落落落洛克
2021/01/08
2.1K0
React系列-自定义Hooks很简单
相关推荐
useContext
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验