纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

React全局状态管理 React全局状态管理的三种底层机制探究

zxg_神说要有光   2021-09-14 我要评论
想了解React全局状态管理的三种底层机制探究的相关内容吗zxg_神说要有光在本文为您仔细讲解React全局状态管理的相关知识和一些Code实例欢迎阅读和指正我们先划重点:react全局状态管理,react状态管理,react底层原理下面大家一起来学习吧

前言

现代前端框架都是基于组件的方式来开发页面按照逻辑关系把页面划分为不同的组件分别开发不同的组件然后把它们一层层组装起来把根组件传入 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 组件用 Providerfunction 组件用 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


相关文章

猜您喜欢

  • Spring使用@MapperScan 解决Spring使用@MapperScan问题

    想了解解决Spring使用@MapperScan问题的相关内容吗「已注销」在本文为您仔细讲解Spring使用@MapperScan的相关知识和一些Code实例欢迎阅读和指正我们先划重点:Spring使用,Spring,@MapperScan下面大家一起来学习吧..
  • Vue.js之render函数 Vue.js之render函数使用详解

    想了解Vue.js之render函数使用详解的相关内容吗猫老板的豆在本文为您仔细讲解Vue.js之render函数的相关知识和一些Code实例欢迎阅读和指正我们先划重点:vue.js,render,vue.js,render详解下面大家一起来学习吧..

网友评论

Copyright 2020 www.sopisoft.net 【绿软下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式