如何利用 React Hooks 管理全局状态

如何利用 React Hooks 管理全局状态

本文写于 2020 年 1 月 6 日

React 社区最火的全局状态管理库必定是 Redux,但是 Redux 本身就是为了大型管理数据而妥协设计的——这就会让一些小一点的应用一旦用上 Redux 就变得复杂无比

后来又有了 Mobx,它对于小型应用的状态管理确实比 Redux 简单不少。可是不得不说 Mobx+React 简直就是一个繁琐版本的 Vue。所以我也不太喜欢,不如直接用 Vue3。

总而言之,不管是 react-redux 还是 mobx,他们使用的时候都非常复杂,甚至需要你去组件函数或是组件类上修修改改,从审美角度上来说就令人不太喜欢。

直到后来某一天用了 Angular,我就开始对 SOA 产生好感,ng 的 Service 的写法与依赖注入控制反转着实惊艳到了我。

Service 是 Angular 的逻辑复用方法,并且解决了共享状态的问题,那 React 的自定义 Hook 可以达到类似的效果嘛?

可以,并且会比 Angular 更简洁!!!

什么是 Service

我们先来想一下,Service 到底是什么?

  • Service 包含 n 个方法;
  • Service 包含有状态;
  • Service 应该是个单例。
  • 这些方法与状态应该是高度整合的,一个 Service 解决的是一个模块的问题。

例如下面这个负责 Todo List 记录的 Service:

class TodoRecordService {
  private todoList: Record[] = [];

  get getTodoList() {
    return this.todoList;
  }

  public addRecord(newRecord: Record) {
    this.todoList.push(newRecord);
  }

  public deleteRecord(id: string) {
    this.todoList = this.todoList.filter((record) => record.id !== id);
  }

  public getRecord(id: string) {
    const targetIndex = this.todoList.findIndex((record) => record.id === id);
    return { index: targetIndex, ele: this.todoList[targetIndex] };
  }
}

自定义 Service

那我们用 React 如何实现一个状态共享的单例呢?

使用 ContextuseContext 即可。

接下来我们做一个最简单的计数器吧:一个负责计数的 button,一个负责显示当前数值的 panel。

const App: React.FC = () => {
  return (
    <div>
      <Button />
      <Panel />
    </div>
  );
};

然后我们来定义我们的 Service:

interface State {
  count: number;
  handleAdd: () => void;
}

export const CountService = createContext<State>(null);

我们选择让一个 Context 成为一个 Service,这是因为我们可以利用 Context 的特性来进行状态共享,达到单例的效果。

但是光这样还不行,我们想让 count 拥有响应性,就必须使用 useState(或者其他 hook)来创建。

因此需要一个自定义 Hook,并且在 Context.Provider 中传入 Providervalue 值:

interface State {
  count: number;
  handleAdd: () => void;
}

export const CountService = createContext<State>(null);

export const useRootCountService = () => {
  const [count, setCount] = useState<number>(0);
  const handleAdd = useCallback(() => {
    setCount((n) => n + 1);
  }, []);

  return {
    count,
    handleAdd,
  };
};

那么在组建中,我们如何使用 Service 呢?

非常简单:

const App: React.FC = () => {
  const countService = useContext(CountService);

  return <div>{countService.count}</div>;
};

所以计数器的完整代码应该这么写:

import { CountService, useRootCountService } from './service/count.service';

const App: React.FC = () => {
  return (
    <CountService.Provider value={useRooCountService()}>
      <div>
        <Button />
        <Panel />
      </div>
    </CountService.Provider>
  );
};

// Button.tsx
import { CountService } from '../services/global.service';

const Button: React.FC = () => {
  // 注意,此处是故意写复杂了,是为了凸显跨组件状态管理的特性
  const countService = useContext(CountService);
  return <button onClick={() => countService.handleAdd()}>+</button>;
};

// Panel.tsx
import { CountService } from '../services/global.service';

const Panel: React.FC = () => {
  const countService = useContext(CountService);
  return <h2>{countService.count}</h2>;
};

hooks 与 Service

对于小组件而言,刚刚的写法已经足够了。

但是要知道,Service 是高度集中的某个模块的状态与方法,我们不能保证 Service 的方法可以直接用到组件的逻辑中去。

所以需要我们在组件内部对于逻辑进行二次拼装。

但是把逻辑直接写到组件里面是一件非常恶劣的事情!!!

幸好,React 有了 hooks 让我们去抽离逻辑代码。

const useLogic1 = () => {
  // 在 hook 中获取服务
  const xxxService = useContext(XxxService);
  // ...
  const foo = useCallback(() => {
    // ...
    xxxService.xxxx();
    // ...
  }, []);

  return {
    // ...
    foo,
  };
};

const SomeComponent: React.FC = () => {
  // 复用逻辑
  const { a, b, foo } = useLogic1(someParams);
  const { c, bar } = useLogic2();

  return (
    <div>
      <button onClick={() => bar()}>Some Operation</button>
    </div>
  );
};

这种形式的组件,便是我们的目标。

(完)

(0)

相关推荐

  • 一切前端概念,都是纸老虎

    (给前端大学加星标,提升前端技能.) 作者:姜小抖 https://zhuanlan.zhihu.com/p/53599723 这篇文章试着聊明白这一堆看起来挺复杂的东西.在聊之前,大家要始终记得一句 ...

  • React笔记03:props、组件通讯、非受控组件

    非受控组件(了解) 借助于 ref 就可以通过 非受控组件 的方式,来获取到的表单元素的值. ref 的作用:获取DOM对象或组件. import React from 'react'; import ...

  • ReactHook快速上车

    React16.8开始内置了10个Hook,核心是2个: 状态管理:useState 副作用管理:useEffect 有状态的函数 useState 有状态组件写法: class Example ex ...

  • hooks 与 animejs

    hooks 与 animejs 本文写于 2020 年 1 月 13 日 animejs 是现如今非常不错的一个 js 动画库.我们将其与 React Hooks 融合,使它更方便的在 React 中 ...

  • react 读书笔记

    来源掘金小册 - react实战:设计模式和最佳实践 react设计思想 属性展开 - 保留当前组件需要的props,并且使其他的props传递下去 var obj = {a: 1, b: 2, c: ...

  • react使用ant design RangePicker 报错invalid hook call

    在使用 RangePicker 前正常,引入RangePicker 后报如下错误: 但是我项目中并没有使用hook,按照提示的可能原因,猜想是版本不兼容问题,看了一下antd版本为4.5.4,eact ...

  • 前端测试的反模式

    在为前端项目编写测试用例的时候,你也许和我一样,曾遇到过以下困扰: 明明进行了功能正确的改动,测试却挂了.修复测试有时候得认真阅读各种mock的细节,或者去了解很多本没有必要知道的代码逻辑.最后修测试 ...

  • Vue3 到底哪里好?和React Hook对比有啥有优势?本文详解

    前言 这几天 Vue 3.0 Beta 版本发布了,本以为是皆大欢喜的一件事情,但是论坛里还是看到了很多反对的声音.主流的反对论点大概有如下几点: 意大利面代码结构吐槽: "太失望了.杂七杂 ...

  • react hooks系列之useRef

    react hooks是 react 16.8 引入的特性,这里我们通过对react-hook-form进行分析来了解成熟的库是如何使用hook的.这将是一个系列,首先推荐 useRef 简介 在re ...

  • 刷新视频超分新记录28.41dB!同时利用过去和未来隐状态的全局视频超分方案OVSR

    作者丨happy 审稿丨邓富城 编辑丨极市平台 极市导读 本文是武汉大学&哈尔滨工业大学&武汉理工在视频超分领域的一次突破性的成果.在深入分析多帧超分.递归超分以及混合框架超分存在的问 ...

  • vue系列教程之微商城项目|vuex全局状态管理-加入购物车

    问题描述 vuex简介 vuex是vue项目中用于管理全局状态的插件,如果对状态二字不明了,就简单理解成全局变量即可. 全局状态管理方式有很多,千奇百怪,比如bus总线.自定义一个js文件等,感兴趣可 ...

  • 【班主任管理篇】借力班级优化大师,成就班级管理大师——利用班级优化大师管理班级的策略与措施

    作者简介 叶巧弟,任职于东莞市大朗镇巷头小学.小学一级数学教师,东莞市第一批小学数学教学能手,大朗镇小学数学学科带头人,多次被评为大朗镇优秀教师.大朗镇优秀班主任.参与省.市级课题研究并结题,多篇论文 ...

  • 企业如何才能有效利用六西格玛管理方法

    企业如何才能有效利用六西格玛管理方法 1.把战略和六西格玛真正结合起来 某财经杂志调查发现,70%失败的CEO并非战略拙劣,而是战略未落实.这个调查反过来告诉我们,在任何市场上,只要把战略执行到位,就 ...

  • OKR如何让全公司进入目标式管理的状态中?

    很怀念小时候,那时报纸.杂志.电视和广播是我们的灯塔,图书馆是我们的星辰大海.那时我们的记忆力好于体力,没有云存储,只有脑回路. 这是申鹤公众号第731天的第725篇原创文章 一家公司要用什么样的方式 ...

  • 613.Outlook技巧: 如果利用Outlook高效管理邮件?

    Outlook技巧: 如果利用Outlook高效管理邮件? Outlook中的信件猛增,如何让邮箱更好的管理,更容易被查询?分享自己的几个Outlook经验和方法,介绍给大家.. 1.开启" ...

  • 不善利用绩效进行管理的领导者,不是一个优秀的领导者

    体育竞技的本质就是竞争,比如奥运会,全世界的运动健儿,十年如一日地刻苦训练,就是为了能够登上奥运会万众瞩目的最高领奖台,为国家争得荣誉.有些人获得了世界冠军,比如刘翔.王濛.孙杨:有些人还在为最高荣誉 ...

  • React Hooks

    Hooks介绍 之前没有用hooks写react的时候,用class类组件,state在构造函数定义,然后是钩子函数. 在这里,发现用的是函数组件,useState来定义state,useEffect ...

  • CVS如何利用数字化工具管理患者,有效提升患者用药依从性的?

    治疗一些复杂的慢性病或急性病,通常需要时间和金钱上的大量投入,其中涉及医疗领域的四个方面--患者.医疗服务提供方.保险公司和医药企业.他们需要通过协调合作,来取得最佳的结果. 减少高需求患者的成本和改 ...