概述

Redux 本身是个极其简单的状态管理框架, 它的简单体现在概念少, 流程明确. 但是, 正是因为简单, 使用上没有强制的约束, 所以如果用不好, 反而会让状态管理更加混乱.

我觉得, 用好 Redux, 首先必须了解其中的几个基本概念, 不只是看看文档, 了解它们的定义, 关键是理解其和整个状态管理的关系. 其次, 要能将这些概念对应到具体的业务系统中, 通过这些概念来规划业务系统的状态管理.

Redux 核心和原则

Redux 核心或者说目的一句话就能概括, 清晰的描述应用的状态 . Redux 提供的 API 没有什么神奇之处, 只是为了实现这个核心而提供的一些工具而已, 不用这些 API 一样能实现 Redux 的状态管理.

Redux 提出的所谓 3 条原则, 其实并不是框架中的约束, 框架对于你如何组织代码其实是极其自由的. 这 3 条原则, 是在自己组织状态管理时, 需要时时记在心里, 自己来控制代码不要违反原则.

  1. 这个应用的状态是一个唯一的状态树
  2. 状态是只读的, 只能通过 action 来触发修改, 其实实际修改状态的是 reducer
  3. 修改状态只能通过纯函数

Redux 中的概念

了解 Redux 中的基本概念, 有助于组织出符合 redux 风格的状态管理, 仅仅使用 redux API 来管理状态, 并不是真正的 redux. Redux 中的概念主要有:

  • state
  • reducer
  • action

其他都是基于这 3 个概念衍生出来的, 这 3 个概念和 Redux 的状态处理流程息息相关.

data flow

严格的单向数据流 , 整个 Redux 都是围绕它来组织的.

单向的数据流, 明确每次 state 的改变, 确保整个应用的状态变化清晰, 可追溯.

reducer

reducer 就是实际改变 state 的函数, 在 redux 中, 也只有 reducer 能够改变 state. 这时再看 redux 的 3 个原则, 我们在组织代码时必须确保 reduer 是纯函数.

根据 redux 的原则, 整个应用只有一个唯一的状态树, 这样, 理论上只要一个 reducer 就够了. 但是, 实际编码时, 如果应用稍具规模, 只有一个 reducer 文件, 显然不利于分模块合作开发, 也不利于代码维护.

所以, reduer 一般是按模块, 或者根据你所使用的框架来组织, 会分散在多个文件夹中. 这时, 可以通过 redux 提供的 API combineReducers 来合并多个 reducer, 形成一个唯一的状态树.

reducer 的使用只要注意 2 点:

  • 必须是纯函数
  • 多个 reducer 文件时, 确保每个 reducer 处理不同的 action, 否则可能会出现后面的 reducer 被覆盖的情况

state

state 或者说是 store, 其实就是整个应用的状态. 其中, 哪些内容是 state? 哪些不是? 哪些要放在 state 中管理? 哪些由页面自己管理? 等等是关键. state 定义的好坏直接影响了应用的维护性和扩展性, 反而是用哪种状态管理框架无关紧要.

很多应用其实是用了很前沿的状态管理技术或者框架, 花了很多时间去熟悉框架的使用, 理解框架的概念, 但是却没有好好定义应用的状态, 被管理的状态如果本身就乱, 管理的再好也没用.

一般, 状态管理框架都有个 计算属性 的概念, redux 也有, 计算属性 在 redux 中的实现有 2 种方式,

  1. 通过 reducer, 定义一些计算属性(本质上还是 state), 在改变 state 的时候同时修改这些计算属性.
  2. 通过 selector, 这个是专门用于 redux 库的 selector. reselect

第二种方案是比较通用的, 也是后面示例中使用的方式

action

redux 中的 action 其实就是一个 包含 type 字段的 plain object. type 字段决定了要执行那个 reducer, 其他字段作为 reducer 的参数.

action creator

action creator 本质是一个函数, 返回值是一个满足 action 的定义的 plain object. 使用 action creator 的目的就是简化 action 的定义, 比如:

const action1 = { type: 'CONNECT', palyload: {user: 'xxx', passwd: 'yyy'}}
const action2 = { type: 'CONNECT', palyload: {user: 'zzz', passwd: 'aaa'}}

这种情况下, 就可以用 action creator 来简化:

const actionCreator = (payload) => ({type: 'CONNECT', payload})

async action

redux 本身的 action 都是是同步的, 但是可以通过如下方法完成异步操作.

const asyncAction = (payload, dispatch) => {
fetchAPI('xxx_url')
.then(result => dispatch({type: 'SUCCESS', payload: result}))
.catch(e => dispatch({type: 'FAILED', error: e}))
} // call async action
asyncAction(payload, store.dispatch)

这样虽然可以完成异步的操作, 但是使用上看起来已经不是 redux 风格的 action 了. 为了保持同步和异步的一致性, 可以通过 middleware 的方式来让 redux 支持异步的 action.

middleware

redux 的 middleware 发生在 dispatching an action 和 reaches the reducer 之间. 在这个时间点, 除了可以实现异步操作, 还可以实现 logging, 路由, 崩溃报告等等.

用 middleware(redux-thunk) 改造上面的异步操作, 让其看起来和其他 redux action 一样.

// createStore 时 applyMiddleware
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk' const store = createStore(
rootReducer,
applyMiddleware(thunk)
)
const asyncAction = (payload) => {
return dispatch => {
fetchAPI('xxx_url')
.then(result => dispatch({type: 'SUCCESS', payload: result}))
.catch(e => dispatch({type: 'FAILED', error: e}))
}
} // call asyncAction
store.dispatch(asyncAction(payload))

asyncAction 的功能和上面一样, 只是使用上更像 redux. redux-thunk middleware 没有什么神奇之处, 它所做的事情就是在 dispatch(function) 的时候, 把 dispatch 作为参数传给 function. 不用 redux-thunk, 只能 dispatch(object), 这里的 object 是描述 action 的 plain object.

Redux 示例(包含计算属性)

完整的示例参见: redux-sample

action:

export const CHANGE_NUM = 'CHANGE_NUM'

export const actionChangeNumCreator = num => {
return {
type: CHANGE_NUM,
num
}
}

reducer:

import { CHANGE_NUM } from '../actions/action'

export const multiReducer = (state = { num: 1 }, action) => {
switch (action.type) {
case CHANGE_NUM:
return { num: action.num }
default:
return state
}
}

selector:

import { createSelector } from 'reselect'

export const mult2Num = createSelector(
state => state.num,
num => {
return num * 2
}
) export const mult3Num = createSelector(
state => state.num,
num => {
return num * 3
}
)

UI 部分:

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { mult2Num, mult3Num } from './selectors/selector'
import { actionChangeNumCreator } from './actions/action'
import { Input } from 'antd'
import './App.css' class App extends Component {
render() {
const { num, num2, num3, changeNum } = this.props return (
<div className="App">
<Input defaultValue={num} onChange={changeNum} />
<p>num*2 = {num2}</p>
<p>num*3 = {num3}</p>
</div>
)
}
} const mapStateToProps = state => {
return {
num: state.num,
num2: mult2Num(state),
num3: mult3Num(state)
}
} const mapDispatchToProps = dispatch => {
return {
changeNum: e => {
dispatch(actionChangeNumCreator(e.target.value))
}
}
} export default connect(
mapStateToProps,
mapDispatchToProps
)(App)

补充-thunk 介绍

thunk 的概念来源于函数式编程, thunk 本身其实就是一个函数, 这个函数会在某个其他函数执行时才执行. thunk 最主要的用途就是延迟某些操作的执行.

redux-thunk middleware 也就是插入一个函数, 这个函数在 dispatch(function)时执行. 上面 asyncAction 的例子中, 这个 thunk 函数就是:

dispatch => {
fetchAPI('xxx_url')
.then(result => dispatch({type: 'SUCCESS', payload: result}))
.catch(e => dispatch({type: 'FAILED', error: e}))
}

redux 简介的更多相关文章

  1. React从入门到放弃之前奏(3):Redux简介

    安装 npm i -S redux react-redux redux-devtools 概念 在redux中分为3个对象:Action.Reducer.Store Action 对行为(如用户行为) ...

  2. Flux架构与Redux简介

    Flux架构区别于传统的MVC架构 在facebook实践中, 当用户接收到新消息时,右上角会弹出你有一条新消息, 右下角的对话框也会提示有新消息, 如果用户在对话框中查看了新消息,那么右上角的这个新 ...

  3. Redux教程1:环境搭建,初写Redux

    如果将React比喻成士兵的话,你的程序还需要一位将军,去管理士兵(的状态),而Redux恰好是一位好将军,简单高效: 相比起React的学习曲线,Redux的稍微平坦一些:本系列教程,将以" ...

  4. React-Native 之 redux 与 react-redux

    前言 本文 有配套视频,可以酌情观看. 文中内容因各人理解不同,可能会有所偏差,欢迎朋友们联系我讨论. 文中所有内容仅供学习交流之用,不可用于商业用途,如因此引起的相关法律法规责任,与我无关,如文中内 ...

  5. Redux(mvc、flux、react-redux)

    其他章节请看: react实战 系列 Redux 关于状态管理,在 Vue 中我们已经使用过 Vuex,在 spug 项目中我们使用了 mobx,接下来我们学习 Redux. 本篇以较为易懂的方式讲解 ...

  6. React.js 入门与实战之开发适配PC端及移动端新闻头条平台课程上线了

    原文发表于我的技术博客 我在慕课网的「React.js 入门与实战之开发适配PC端及移动端新闻头条平台」课程已经上线了,文章中是目前整个课程的大纲,以后此课程还会保持持续更新,此大纲文档也会保持更新, ...

  7. immutable.js 在React、Redux中的实践以及常用API简介

    immutable.js 在React.Redux中的实践以及常用API简介 学习下 这个immutable Data 是什么鬼,有什么优点,好处等等 mark :  https://yq.aliyu ...

  8. Redux 和 React-Redux简介

    先说一下,为什么会产生Redux这样的框架,我们在开发React应用时,会发现组件之间需要进行数据的交换和传递.体现在: 1. 父组件要向子组件传递数据 通过修改子组件的props 2. 兄弟组件之间 ...

  9. 动手实现 Redux(三):纯函数(Pure Function)简介

    我们接下来会继续优化我们的 createStore 的模式,让它使我们的应用程序获得更好的性能. 但在开始之前,我们先用一节的课程来介绍一下一个函数式编程里面非常重要的概念 —— 纯函数(Pure F ...

随机推荐

  1. 禁止WPS2019开机自启动

    最近开机发现WPS总是自己启动,导致开机速度会慢5s左右,从网上找了很多办法都没用,包括运行+msconfig,启动项里面没有WPS:杀毒软件自启动管理里面也没有找到WPS,百度了一圈也没有找到任何有 ...

  2. Java的Random类详解

    Random类专门用于生成一个伪随机数,它有两个构造器:一个构造器使用默认的种子(以当前时间作为种子),另一个构造器需要程序员显示传入一个long型整数的种子. Random类比Math类的rando ...

  3. 数组for循环查找范围

    数组for循环查找范围,如果是判读是否在键值之间,如$array[$i],那么接邻的元素不能用$array[$i+1]或者$array[$i-1]只能用$array[$i++]

  4. 深入理解Java虚拟机-第1章-走进Java-读书笔记

    第 1 章 走近 Java 前言 Java 的技术体系主要是由支撑 Java 程序运行的虚拟机.为各开发领域提供接口支持的 Java API.Java 编程语言及许许多多的第三方 Java 框架(如 ...

  5. 开发人员的必备工具Git(初级)

    Git是什么 Git是目前世界上最先进的分布式版本控制系统. 这个软件用起来就应该像这个样子,能记录每次文件的改动: 举个栗子 :       版本 用户 说明 日期 1 张三 删除了软件服务条款5 ...

  6. AI - TensorFlow - 分类与回归(Classification vs Regression)

    分类与回归 分类(Classification)与回归(Regression)的区别在于输出变量的类型.通俗理解,定量输出称为回归,或者说是连续变量预测:定性输出称为分类,或者说是离散变量预测. 回归 ...

  7. .NET Core微服务之基于Ocelot实现API网关服务(续)

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.负载均衡与请求缓存 1.1 负载均衡 为了验证负载均衡,这里我们配置了两个Consul Client节点,其中ClientServic ...

  8. 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇

    前言 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一.Android系统的运行由大量相互独立的进程相互协助来完成的,所以Android进程间通信问题,是做好Andro ...

  9. .NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了

    最近有个需求就是一个抽象仓储层接口方法需要SqlServer以及Oracle两种实现方式,为了灵活我在依赖注入的时候把这两种实现都给注入进了依赖注入容器中,但是在服务调用的时候总是获取到最后注入的那个 ...

  10. RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2版本正式发布

     RDIFramework.NET .NET快速信息化系统开发框架 V3.2版本 正式发布 精益求精求完美! 1.RDIFramework.NET框架介绍 RDIFramework.NET,基于.NE ...