返回顶部
首页 > 资讯 > 前端开发 > JavaScript >前端的状态管理(下)
  • 910
分享到

前端的状态管理(下)

2024-04-02 19:04:59 910人浏览 泡泡鱼
摘要

目录1、Redux1.1、Store(图书馆管理员)1.2、State(书本)1.3、Action(借书单)1.4、store.dispatch (提交借书单)1.5、Reducer

前言:

续上篇前端的状态管理(上),没想到很多读者朋友们这么关注,感谢大家的支持和建议,我只是发表个人看法以及自己的一些思考也许不够全面,使用 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 不就好了?跨路由跳转还得手动清除状态防止警告。。。仁者见仁,智者见智吧。自己封装了也说明自己有所研究,不论他易或难,编程本身不就该是不断探索吗,哈哈。尽管你写的可能不够好或是咋样,虚心接受批评就是了,毕竟厉害的人多着呢。

总结:

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

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

--结束END--

本文标题: 前端的状态管理(下)

本文链接: https://lsjlt.com/news/154810.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 前端的状态管理(下)
    目录1、Redux1.1、Store(图书馆管理员)1.2、State(书本)1.3、Action(借书单)1.4、store.dispatch (提交借书单)1.5、Reducer...
    99+
    2024-04-02
  • 前端的状态管理(上)
    目录1、什么是前端状态管理?2、Vuex3、Bus 总线4、web storage前言: 提到状态管理大家可能马上就想到:Vuex、Redux、Flux、Mobx等等方案。其实不然...
    99+
    2024-04-02
  • vue前端开发辅助函数状态管理详解示例
    目录mapStatemapGettersmapMutationsmapActions示例小结mapState 当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗...
    99+
    2024-04-02
  • Angular 中的状态管理
    在Angular中,可以使用各种库和模式来管理应用程序的状态。以下是一些常见的Angular状态管理解决方案:1. 内置的RxJS:...
    99+
    2023-09-21
    Angular
  • Vue 状态管理策略:从单一状态树到分布式状态管理
    1. Vuex:单一状态树 Vuex 是 Vue 官方推荐的状态管理库,它采用单一状态树的模式,将所有状态集中管理在一个对象中。这使得状态更容易追踪和修改,提高了代码的可维护性。 // store.js import Vuex from...
    99+
    2024-02-24
    Vue 状态管理 Vuex Pinia 状态共享 状态隔离 状态持久化
  • react怎么管理状态
    这篇文章主要介绍“react怎么管理状态”,在日常操作中,相信很多人在react怎么管理状态问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”react怎么管理状态”的疑惑有所帮...
    99+
    2024-04-02
  • Vue之Pinia状态管理
    目录一、认识Pinia1.1 认识Pinia1.2 为什么使用Pinia?二、 Store2.1 定义Store2.2 Option对象2.3 setup函数2.4 使用定义的Sto...
    99+
    2023-05-14
    Javascript Vue Pinia状态管理 Vue Pinia状态管理 Pinia状态管理
  • linux下怎么查看SELinux的当前状态
    本篇内容介绍了“linux下怎么查看SELinux的当前状态”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. sestatus命令输出说明...
    99+
    2023-06-15
  • Linux下怎么用netstat查看网络状态、端口状态
    这篇文章给大家分享的是有关Linux下怎么用netstat查看网络状态、端口状态的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。      netstat命令是一个监控TCP...
    99+
    2023-06-04
  • javascript Redux的状态管理详解
    所谓的状态管理,就是对应用程序中的数据进行管理。 理念:凡是数据流管理混乱的项目,几乎都上不了线。好的项目,必须有非常良好的数据流管理。 如何使用Redux?记住“3个3...
    99+
    2024-04-02
  • flutter 常见的状态管理器
    flutter 常见的状态管理器 前言一、Provider二、Bloc三、Redux四、GetX总结 前言 当我们构建复杂的移动应用时,有效的状态管理是至关重要的,因为应用的不同部分可...
    99+
    2023-09-03
    flutter javascript 前端
  • Linux下如何查看端口状态
    这篇文章将为大家详细讲解有关Linux下如何查看端口状态,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。查看具体端口号的状态。如果是非root用户,命令前还要加sudo进行提权。netstat -...
    99+
    2023-06-27
  • Angular需要状态管理吗
    这篇文章主要讲解了“Angular需要状态管理吗”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Angular需要状态管理吗”吧!在Angular中不是必须要...
    99+
    2024-04-02
  • 详解Vue3-pinia状态管理
    目录pinia是什么?官网安装命令使用pinia是什么? 这个是 vue3 新的状态管理工具,简单来说相当于之前 vuex,它去掉了 Mutations 但是也是支持 vue2 的,...
    99+
    2022-11-13
    Vue3-pinia状态管理 Vue3状态管理 Vue3 pinia状态管理 vue pinia是什么
  • vuex状态管理数据状态查询与更改的方法
    本篇内容介绍了“vuex状态管理数据状态查询与更改的方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!状态管理数据状态查询与更改1.main...
    99+
    2023-06-30
  • 「Flink」Flink的状态管理与容错
    在Flink中的每个函数和运算符都是有状态的。在处理过程中可以用状态来存储数据,这样可以利用状态来构建复杂操作。为了让状态容错,Flink需要设置checkpoint状态。Flink程序是通过checkpoint来保证容错,通过c...
    99+
    2019-08-30
    「Flink」Flink的状态管理与容错
  • Vue3状态管理的使用详解
    目录背景 Provide / Inject 抽离共享状态提供数据 注入数据 小结 reactive 抽离共享状态使用共享状态 小结 结语 背景 随着Vue3的逐步应用,对状态管理的...
    99+
    2024-04-02
  • ReactMobx状态管理工具的使用
    目录Mobx与redux的区别使用安装observable&&autorunaction使用装饰器写法runInAction(异步)Mobx与redux的区别 mob...
    99+
    2023-02-06
    React Mobx React Mobx状态管理 React状态管理
  • vue状态管理实例分析
    这篇文章主要介绍“vue状态管理实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue状态管理实例分析”文章能帮助大家解决问题。场景:一个地图应用,有个侧边栏...
    99+
    2024-04-02
  • Android 状态管理之Lifecycle浅析
    目录原理概述构成模型源码1. addObserver(observer)2. sync()3. setCurrentState、moveToState监听其他1. Applicati...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作