前端的状态管理(下)

目录
  • 1、Redux
    • 1.1、Store(图书馆管理员)
    • 1.2、State(书本)
    • 1.3、Action(借书单)
    • 1.4、store.dispatch (提交借书单)
    • 1.5、Reducer(包装书本)
  • 2、状态管理的目的

前言:

续上篇前端的状态管理(上),没想到很多读者朋友们这么关注,感谢大家的支持和建议,我只是发表个人看法以及自己的一些思考也许不够全面,使用 Vue 举例也仅仅只是作为引路且 Vue 的关注度也是较高的。那有些朋友想听听除 Vuex 的其他方案,今天将从 Redux 入手逐渐拓展(如标题一样浅谈)。

1、Redux

作为 React 全家桶的一员,Redux 试图为 React 应用提供可预测化的状态管理机制。和大多数状态管理方案一样,Redux 的思想也是发布订阅模式,我们还是以图书馆为例来简单了解一下 Redux。

Redux 的基础操作大致为:

  • Store(图书馆管理员)
  • State(书本)
  • Action(借书单)
  • store.dispatch(提交借书单)
  • Reducer(包装书本)
  • store.subscribe(接收书本)

1.1、Store(图书馆管理员)

Store 可以看作是一个容器,整个应用只有一个 Store。就好比你想要借书只能找图书管理员。

import { createStore } from 'redux'
const store = createStore(reducer);

1.2、State(书本)

对于 State 来说他只能通过 Action 来改变(既你借书只能提交借书单来借),不应该直接修改 State 里的值。

使用store.getState()可以得到state

import { createStore } from 'redux'
const store = createStore(reducer)
store.getState()

1.3、Action(借书单)

你想借书咋办?那当然是向管理员提交借书单了。那用户是接触不到 State 的,只能通过 View (视图)去操作(如点击按钮等),也就是 State 的变化对应 View 的变化,就需要 View 提交一个 Action 来通知 State 变化。(既通过提交借书单给管理员才会有接下来一系列的其他操作)

Action 是一个自定义对象,其中type属性是约定好将要执行的操作。

const action = {
    type: 'click',
    info: '提交借书单'
}

1.4、store.dispatch (提交借书单)

store.dispatch 是 View 发出 Action 的唯一方法,他接受一个 Action 对象(既提交借书单),只是把单的信息给了图书管理员,他在根据单子来搜索相应的书本。

store.dispatch(action)

1.5、Reducer(包装书本)

Store 收到一个 Action 后,必须给出一个新的 State ,这样 View 才会发生变化,而新的 State 的计算过程就是 Reducer 来完成的。(既拿到单子将你的书本打包装袋等)

Reducer 是一个自定义函数,它接受 Action 和当前的 State 作为参数,返回一个新的 State。

const reducer = (state, action) => {
    return `action.info: ${state}` // => 提交借书单:红楼梦
}

store.subscribe(接收书本)
当 State 一旦发生变化,那么 store.subscribe() 就会监听到自动执行更新 View。

const unsubscribe = store.subscribe(() => {
  render() {
    // 更新view
  }
})
// 也可以取消订阅(监听)
unsubscribe()

小结:

相信刚接触 Redux 的同学都会觉得 Redux 比较繁琐,这也与他的思想有关:Redux 里的一切应该都是确定的。

尽管在 Redux 里还是没办法做到一切都是确定的(如异步)但是应该保证大多数部分都是确定的包括:

  • 视图的渲染是可确定的
  • 状态的重建是可确定的

至于为什么要这么做,上一篇我已有提及。他的重要之处在于:便于应用的测试,错误诊断和 Bug 修复。

2、状态管理的目的

那其实大多数程序员使用 Redux 的最多的场景无非是从 A 页面返回 B 页面 需要保存 B 页面的状态。

倘若项目不大,用 Redux 或 Vuex 是不是会显得有些大?我们知道在 Vue 中有提供 keep-alive 让我们缓存当前组件,这样就可以解决上述的场景。

但是很遗憾在 React 中并没有像 Vue 一样的 keep-alive。社区中的方案普遍是改造路由,但是这种改造对于项目入侵过大且不易维护,另外在 react-router v5 中也取消了路由钩子。于是,对小型项目来说自己封装一个函数也不失为良策。(当然你想用 Redux 也没问题,咱们只是探索更多方式)

还是用图书馆来举例子,现在有一个图书馆管理系统,你从列表页(list)跳入详情页(detail)需要保存列表页的状态(如搜索栏的状态等)。

假设你使用的技术栈是(react + antd),来手写一个简单粗暴的(核心是利用context来进行跨组件数据传递):

// KeepAlive.js
export default function keepAliveWrapper() {
  return function keepAlive(WrappedComponent) {
    return class KeepAlive extends WrappedComponent { // ps
      constructor(props) {
        super(props)
        // do something ...
      }

      componentDidMount() {
        const {
          keepAlive: { fieldsValue },
        } = this.context
        // do something ...
        super.componentDidMount()

      }

      render() {
        // do something ...
        return super.render()
      }
    }
  }
}

这里提一下为什么要继承原组件(// ps)

如果常规写法返回一个类组件(class KeepAlive extends React.Component),那本质上就是父子组件嵌套,父子组件的生命周期都会按秩序执行,所以每当回到列表页获取状态时,会重复渲染两次,这是因为 HOC 返回的父组件调用了原组件的方法,到导致列表页请求两次,渲染两次。

若使 HOC(高阶组件)继承自原组件,就不会生产两个生命周期交替执行,很好的解决这个问题。

// main.jsx 根组件
import React from 'react'

const appContext = React.createContext()

class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
          keepAlive: {}, // 缓存对象
          isCache: false, // 是否缓存
          fieldsValue: {} // 缓存表单值
        }
    }
    componentDidMount() {
        // 初始化
        const keepAlive = {
          isCache: this.state.isCache,
          toggle: this.toggleCache.bind(this),
          fieldsValue: this.state.fieldsValue,
        }
        this.setState({ keepAlive })
    }
    // 这里封装一个清除状态的方法 防止渲染警告(you can't set fields before render ...)
    // 比如 list1 => list1/detail => list2 需要将跳转放在以下回调中并清除状态
    toggleCache(isCache = false, payload, callback) {
        const { fieldsValue = null } = payload
        const keepAlive = {
          isCache,
          fieldsValue,
          toggle: this.toggleCache.bind(this),
        }
        const fn = typeof callback === 'function' ? callback() : void 0
        this.setState(
          {
            keepAlive,
          },
          () => {
            fn
          }
        )
    }
    render() {
        const { keepAlive } = this.state
        <appContext.Provider value={{ keepAlive }}>
            // your routes...
        </appContext.Provider>
    }

}

至于为什么不直接使用 context,而多封装一层 keepAlive,是为了统一处理 context,在组件头部中使用装饰器这种简洁的写法(@keepAlive)你就立马知道这是一个有缓存的组件(方便阅读及维护)。

// 在页面使用时
import React from 'react'
import keepAlive from '../keepAlive'

// keepAlive的位置需要放在原组件最近的地方
@keepAlive()
class App extends React.Component {
    constructor(props){
        super(props)
        this.state = {
            // init something...
        }
    }
    componentDidMount() {
        // do something...
        if(this.context.keepAlive.fieldsValue) {
            const { tableList } = this.context.keepAlive.fieldsValue
            console.log('缓存啦:',tableList) // 缓存啦:['1', '2']
        }
    }
    // 查看详情
    detail = () => {
        this.context.keepAlive.fieldsValue = {
            tableList: ['1', '2']
        }
        // jump...
    }
    // 当需要跨一级路由进行跳转时,如 list1 => list1/detail(下面这个方法应该在详情页里) => list2,此时需要处理一下警告
    toList2 = () => {
        this.context.keepAlive.toggle(false, {}, () => {
            // jump...
        })
    }
}

在上述使用了装饰器写法,简单说一下,需要先配置以下 babel 放可使用哦~

npm install -D @babel/plugin-proposal-decorators

jsconfig.json中(无则新建)配置一下:

{
    "compilerOptions": {
        "experimentalDecorators": true
    },
    "exclude": [
        "node_modules",
        "dist"
    ]
}

在 .babelrc 配置:

{
    "plugins": [
        "@babel/plugin-proposal-decorators",
        {
            "legacy": true
        }
    ]
}

上面方法比较适用刚才说的场景(从 A 页面返回 B 页面 需要保存 B 页面的状态),有人的说,你这样还不如用 Redux Mobx 不就好了?跨路由跳转还得手动清除状态防止警告。。。仁者见仁,智者见智吧。自己封装了也说明自己有所研究,不论他易或难,编程本身不就该是不断探索吗,哈哈。尽管你写的可能不够好或是咋样,虚心接受批评就是了,毕竟厉害的人多着呢。

总结:

到此这篇关于前端的状态管理的文章就介绍到这了,更多相关前端的状态管理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

回顾上篇:浅谈前端的状态管理(上)

(0)

相关推荐

  • vue前端开发辅助函数状态管理详解示例

    目录 mapState mapGetters mapMutations mapActions 示例 小结 mapState 当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余.为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性.不使用mapState时,获取对象状态,通常放在使用组件的computes属性中,使用方式为: //.... computed: { count: function(){ return this.$store.state

  • 前端的状态管理(上)

    目录 1.什么是前端状态管理? 2.Vuex 3.Bus 总线 4.web storage 前言: 提到状态管理大家可能马上就想到:Vuex.Redux.Flux.Mobx等等方案.其实不然,不论哪种方案只要内容一多起来似乎都是令人头疼的问题,也许你有适合自己的解决方案又或者简单的注释和区分模块,今天来聊一聊前端的状态管理,如果你有好的建议或问题欢迎在下方留言提出. 1.什么是前端状态管理? 举个例子:图书馆里所有人都可以随意进书库借书还书,如果人数不多,这种方式可以提高效率减少流程,一旦人数多

  • 前端的状态管理(下)

    目录 1.Redux 1.1.Store(图书馆管理员) 1.2.State(书本) 1.3.Action(借书单) 1.4.store.dispatch (提交借书单) 1.5.Reducer(包装书本) 2.状态管理的目的 前言: 续上篇前端的状态管理(上),没想到很多读者朋友们这么关注,感谢大家的支持和建议,我只是发表个人看法以及自己的一些思考也许不够全面,使用 Vue 举例也仅仅只是作为引路且 Vue 的关注度也是较高的.那有些朋友想听听除 Vuex 的其他方案,今天将从 Redux 入

  • 详解vuex之store拆分即多模块状态管理(modules)篇

    了解vuex的朋友都知道它是vue用来集中管理状态的容器,如果了解过Reduce的朋友可能看见他时就会非常熟悉,都是用来管理全局的状态的,实现不同组件之间相互的数据访问.这里我们不介绍vuex,主要介绍vuex拆分store以及多模块管理.我们知道如果一个项目非常大的话状态就会非常的多,如果不进行分类处理,所有的状态都维护在一个state里面的话,状态管理就会变得非常的混乱,这样非常不利于项目的后期维护.我们现在前端推崇模块化开发,为的就是提高开发效率和维护效率,避免重复工作.那么vuex是怎么

  • 详解vuex状态管理模式

    一.前言 本次接受一个BI系统,要求是能够接入数据源-得到数据集-对数据集进行处理-展现为数据的可视化,这一个系统为了接入公司自身的产品,后端技术采用spring boot,前端采用vue+vuex+axios的项目架构方式,vuex作为vue的状态管理,是尤为重要的部分.这里,我将vuex如何运作和使用做一次总结,有错的地方,望多多提点. 二.vuex简单使用 安装vuex cnpm install vuex --save 在src目录下建立文件夹,命名为store,建立index.js 如图

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

    目录 前言 props context state 总结 前言 现代前端框架都是基于组件的方式来开发页面.按照逻辑关系把页面划分为不同的组件,分别开发不同的组件,然后把它们一层层组装起来,把根组件传入 ReactDOM.render 或者 vue 的 $mount 方法中,就会遍历整个组件树渲染成对应的 dom. 组件都支持传递一些参数来定制,也可以在内部保存一些交互状态,并且会在参数和状态变化以后自动的重新渲染对应部分的 dom. 虽然从逻辑上划分成了不同的组件,但它们都是同一个应用的不同部分

  • Vue.js 状态管理及 SSR解析

    目录 前端状态管理出现的意义及解决的问题 Vuex 源码解读 Vuex 公共方法 Vuex 介绍及深入使用 Vuex 使用(官网) 1.基本框架 2.基本使用 3.State 3.1 mapState 辅助函数 4.Getter 4.1 通过属性访问 4.2 通过方法访问 4.3 mapGetters 辅助函数 5.Mutation 5.1 提交载荷(Payload) 5.2 使用常量替代 Mutation 事件类型 5.3 Mutation 必须是同步函数 5.4 在组件中提交 Mutatio

  • 浅谈Vuex的状态管理(全家桶)

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试.状态快照导入导出等高级调试功能. 以上是vuex的官方文档对vuex的介绍,官方文档对vuex的用法进行了详细的说明.这里就不再细讲vuex的各个用法,写这篇博客的目的只是帮助部分同学更快地理解并上手vuex.

  • Vue的Flux框架之Vuex状态管理器

    学习vue之前,最重要是弄懂两个概念,一是"what",要理解vuex是什么:二是"why",要清楚为什么要用vuex. Vuex是什么? Vuex 类似 React 里面的 Redux 的状态管理器,用来管理Vue的所有组件状态. 为什么使用Vuex? 当你打算开发大型单页应用(SPA),会出现多个视图组件依赖同一个状态,来自不同视图的行为需要变更同一个状态. 遇到以上情况时候,你就应该考虑使用Vuex了,它能把组件的共享状态抽取出来,当做一个全局单例模式进行管理

  • 一篇看懂vuejs的状态管理神器 vuex状态管理模式

    关于vuex类的新闻最近很多,看到眼热就去查了下资料,然后扯出来一堆flux.redux.state.state之类的概念,以及大型工程必要性之类的.看官方手册也是昏昏然. 然而,我还是弄懂了!我准备从demo出发,以同样的一个最简单的demo,演示两种情况下的代码编写情况: 单纯依赖于vue.js 依赖vue.js,也使用了vuex技术 目的是通过对比引出vuex的概念.优势和劣势.也许这是目前最接地气的vuex的介绍吧:).所以无论如何在了解vuex之前,你必须懂得vue.js(好像废话:)

随机推荐