React 全局状态管理的 3 种底层机制

发表于 3年以前  | 总阅读数:291 次

现代前端框架都是基于组件的方式来开发页面。按照逻辑关系把页面划分为不同的组件,分别开发不同的组件,然后把它们一层层组装起来,把根组件传入 ReactDOM.render 或者 vue 的 $mount 方法中,就会遍历整个组件树渲染成对应的 dom。

组件都支持传递一些参数来定制,也可以在内部保存一些交互状态,并且会在参数和状态变化以后自动的重新渲染对应部分的 dom。

虽然从逻辑上划分成了不同的组件,但它们都是同一个应用的不同部分,难免要彼此通信、配合。超过一层的组件之间如果通过参数通信,那么中间那层组件就要透传这些参数。而参数本来是为了定制组件用的,不应该为了通信而添加一些没意义的参数。

所以,对于组件的通信,一般不会通过组件参数的层层传递,而是通过放在全局的一个地方,双方都从那里存取的方式。

具体的用于全局状态管理的方案可能有很多,但是他们的底层无外乎三种机制:props、context、state。

下面,我们分别来探究一下这三种方式是如何做全局状态的存储和传递的。

props

我们可以通过一个全局对象来中转,一个组件向其中存放数据,另一个组件取出来的方式来通信。

组件里面写取 store 中数据的代码比较侵入式,总不能每个用到 store 的组件都加一段这些代码吧。我们可以把这些逻辑抽成高阶组件,用它来连接(connect)组件和 store。通过参数的方式来把数据注入到组件中,这样,对组件来说来源是透明的。

这就是 react-redux 做的事情:

import { connect } from 'react-redux';

function mapStateToProps(state) {
    return { todos: state.todos }
}

function mapDispatchToProps(dispatch) {
    return bindActionCreators({ addTodo }, dispatch)
}

export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)

此外,redux 还提供了中间件机制,可以拦截组件发送给 store 的 action 来执行一系列异步逻辑。

比较流行的中间件有 redux-thunk、redux-saga、redux-obervable,分别支持不同的方式来写组织异步流程,封装和复用异步逻辑。

类似的其他全局状态管理的库,比如 mobox、reconcil 等,也是通过 props 的方式注入全局的状态到组件中。

context

跨层组件通信一定要用第三方的方案么,不是的,react 本身也提供了 context 机制用于这种通信。

React.createContext 的 api 会返回 Provider 和 Consumer,分别用于提供 state 和取 state,而且也是通过 props 来透明的传入目标组件的。(这里的 Consumer 也可以换成 useContext 的 api,作用一样,class 组件用 Provider,function 组件用 useContext)

看起来和 redux 的方案基本没啥区别,其实最主要的区别是 context 没有执行异步逻辑的中间件。

所以 context 这种方案适合没有异步逻辑的那种全局数据通信,而 redux 适合组织复杂的异步逻辑。

案例代码如下:

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

const ThemeContext = React.createContext(themes.light);

function App() {
  return (
    <ThemeContext.Provider value={themes.dark}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      I am styled by theme context!
    </button>
  );
}

不知道大家有没有想过,props、state 改变了,重新渲染组件很正常,context 改变了,又是怎么触发渲染的呢?

其实 react 内部做了处理,如果改变了 context 的值,那么会遍历所有的子组件,找到用到 context 值的组件,触发它的更新。

所以,props、state、context 都能够触发重新渲染。

state

redux 和 context 的方案,一个是第三方的,一个是内置的,都是通过 props 来传入值或者通过 hooks 来取值,但它们都是组件外部的,而 state 是组件内部的,怎么通过 state 来做全局状态共享呢?

其实 class 组件的 state 做不到,但是 function 组件的 state 可以,因为它是通过 useState 的 hooks api 创建的,而 useState 可以抽离到自定义 hooks 里,然后不同的 function 组件里引入来用。

import React, { useState } from 'react';

const useGlobalState = (initialValue) => {
    const [globalState, setGlobalState] = useState(initialValue);
    return [globalState, setGlobalState];
}

function ComponentA() {
    const [globalState, setGlobalState] = useGlobalState({name: 'aaa'});

    setGlobalState({name: bbb});
    return <div>{globalState}</div>
}

function ComponentA() {
    const [globalState, setGlobalState] = useGlobalState({name: 'aaa'});

    return <div>{globalState}</div>
}

上面这段代码可以共享全局状态?

确实不可以,因为现在每个组件都是在自己的 fiber.memorizedState 中放了一个新的对象,修改也是修改各自的。

那把这两个 useState 的初始值指向同一个对象不就行了?

这样多个组件之间就可以操作同一份数据了。

上面的代码要做下修改:

let globalVal  = {
    name: ''
}

const useGlobalState = () => {
    const [globalState, setGlobalState] = useState(globalVal);

    function updateGlobalState(val) {
        globalVal = val;
        setGlobalState(val);
    }

    return [globalState, updateGlobalState];
}

这样,每个组件创建的 state 都指向同一个对象,也能做到全局状态的共享。

但这里有个前提,就是只能修改对象的属性,而不能修改对象本身。

总结

现在前端页面的开发方式是把页面按照逻辑拆成一个个组件,分别开发每一个组件,然后层层组装起来,传入 ReactDOM.render 或者 Vue 的 $mount 来渲染。

组件可以通过 props 来定制,通过 state 来保存交互状态,这些变了都会自动的重新渲染。除此之外,context 变了也会找到用到 contxt 数据的子组件来触发重新渲染。

组件之间彼此配合,所以难免要通信,props 是用于定制组件的,不应该用来透传没意义的 props,所以要通过全局对象来中转。

react 本身提供了 context 的方案,createContext 会返回 Provider 和 Consumer,分别用来存放和读取数据。在 function 组件中,还可以用 useContext 来代替 Provider。

context 虽然可以共享全局状态,但是却没有异步逻辑的执行机制,当有复杂的异步逻辑的时候,还是得用 redux 这种,它提供了中间件机制用于组织异步流程、封装复用异步逻辑,比如 redux-saga 中可以把异步逻辑封装成 saga 来复用。

context 和 redux 都支持通过 props 来注入数据到组件中,这样对组件是透明的、无侵入的。

其实通过 useState 封装的 自定义 hooks 也可以通过把初始值指向同一个对象的方式来达到全局数据共享的目的,但是是有限制的,只能修改对象的属性,不能修改对象本身。其实用这种还不如用 context,只是提一下可以这样做。

简单总结一下就是:context 和 redux 都可以做全局状态管理,一个是内置的,一个是第三方的,没有异步逻辑用 context,有异步逻辑用 redux。

本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/b9Zv5KmCCQoT8DUnTBv7jw

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237231次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8065次阅读
 目录