概述

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. SQLServer之删除用户自定义数据库用户

    删除用户自定义数据库用户注意事项 不能从数据库中删除拥有安全对象的用户. 必须先删除或转移安全对象的所有权,才能删除拥有这些安全对象的数据库用户. 不能删除 guest 用户,但可在除 master ...

  2. 任务型对话(一)—— NLU(意识识别和槽值填充)

    1,概述 任务型对话系统越来越多的被应用到实际的场景中,例如siri,阿里小密这类的产品.通常任务型对话系统都是基于pipline的方式实现的,具体的流程图如下: 整个pipline由五个模块组成:语 ...

  3. 关于raft算法

    列出一些比较好的学习资料, 可以经常翻一番,加深印象 0 raft官方git 1  raft算法动画演示 2    Raft 为什么是更易理解的分布式一致性算法 3  raft一致性算法 4  Raf ...

  4. .NET Core 给使用.NET的公司所带来的机遇

    今晚在余晟的微信公众号看到了一篇文章< 从.NET/C#开发的“后继无人”说起: https://mp.weixin.qq.com/s/rO2d0xZ58Z2syqT7AaNT3w>. 这 ...

  5. 《Python黑客编程之极速入门》正式开课

    玄魂 玄魂工作室 今天 之前开启了一个<Python黑客编程>的系列,后来中断了,内容当时设置的比较宽,不太适合入门.现在将其拆分成两个系列<Python黑客编程之极速入门>和 ...

  6. 阿里如何实现海量数据实时分析技术-AnalyticDB

    导读:随着数据量的快速增长,越来越多的企业迎来业务数据化时代,数据成为了最重要的生产资料和业务升级依据.本文由阿里AnalyticDB团队出品,近万字长文,首次深度解读阿里在海量数据实时分析领域的多项 ...

  7. mysql性能优化之数据库级别优化--优化sql语句

    一  优化SELECT语句 1.1 WHERE子句优化 本文暂时只讨论可以处理WHERE子句的优化,下面的一些实例使用SELECT语句,但是相同的优化同样适用DELETE和UPDATE语句中的WHER ...

  8. PHP内核之旅-6.垃圾回收机制

    回收PHP 内核之旅系列 PHP内核之旅-1.生命周期 PHP内核之旅-2.SAPI中的Cli PHP内核之旅-3.变量 PHP内核之旅-4.字符串 PHP内核之旅-5.强大的数组 PHP内核之旅-6 ...

  9. 面向对象(__item__)

    #Author : Kelvin #Date : 2019/1/20 21:37 class People: def __getitem__(self, item): print("geti ...

  10. docker~yml里使用现有网络

    回到目录 我们在进行docker swarm部署高可用集群时,在yml文件里可能要配置一些服务,而这些服务可能要使用一些公用的数据库,这些数据库可能已经运行在某个容器里,而这些容器有自己的网络,doc ...