Redux真的让我脑仁疼,感觉有点搞不定他,因为对我而言太抽象了。所以我用通俗易懂地方法去思考Redux,感觉能够理解了。

本文要点:

  • action

    • 配置行为
    • store.dispatch(action)
  • reducer
    • 纯函数
    • 返回新的state
    • createStore(reducer)
  • store
    • getStore
    • dispatch
    • subscribe
  • combineReducers

本文代码仓库,在此文件夹之中。

讲道理我要用import和export的写法来学习Redux,但是node有些es6还是不支持的,为了简单演示,我就用requre和module.exports来演示。(不然我还得讲解下babel转换es6的知识点)

在开始之前,我们是不是应该安装一个redux,然后才能开始愉快地玩耍。

npm install --save redux

action 和 reducer 一对好基友

用Redux创建全局应用数据管理store之前,我们需要创建两个类型的JS文件,一个是action一个是reducer,这两个类型的功能我个人认为很容易搞混。不知道哪个是干什么,经常忘记用法。那我只能通过他们的具体含义来判断他们的用法,而不是死记硬背(哎,年纪大了,记性不好,只能通过理解来记住了。)

一个只知道安排任务的action

首先我们先看action,相信这个单词大家都认识。导演拍戏的时候,都喜欢说action!,这个既有行动的意思,也有开始的意思,在Redux中就是开始行动的意思。也就是说这个action是主动,而非被动的。导演说开始,你就要开始,而且还要按照剧本进行,一切都被安排地明明白白。所以,Redux的action,就是一个指示,告诉store,我要进行这个东西,你给安排下。有时候,我们需要附带点内容到store,才能进行下一步操作,这个时候就需要action携带规范的参数。

所以我们怎么写action呢?包含两点:

  • 注册行为
  • 注册行为所带的参数

注册行为,安排行为,标准每个行为的指令

const todo={
TOGGLE_TODO:'TOGGLE_TODO',
GET_TODOS:'GET_TODOS'
}

配置行为所带的参数,标准化参数,该带上的都带上,以免被退回。其中type是行为的类型,必须有,就像有些office要带门卡一样,忘了就再见!要被保安请出去的。后方的item就是自定义的,看看你的操作需要哪些参数,需要就带上,不需要带上的就不要带上了,哪样就很累赘了。

const todo={
TOGGLE_TODO:'TOGGLE_TODO',
GET_TODOS:'GET_TODOS',
toggleTodo:function ({ items,id }) {
return {
type: todo.TOGGLE_TODO,
items:items
id:id
}
},
getTodos: function getTodos({items}){
return {
type:todo.GET_TODOS,
items:items
}
}
}
module.exports=todo

action只是告诉你发生了什么,给你配齐了参数,但是不执行,不对传入的对象(state)进行改变。*

但是既然action仅仅是配置而已,那么怎么操作呢,之后怎么进行呢?Redux才不会这么好心帮我们把后续操作给搞定了,这个时候我们就要去研究Reducer了,一个我不知道如何翻译的函数。

纯纯的reducer

现在我们来看最无法理解的reducer,为什么他要叫reducer,有什么具体含义吗?还是随便起的名字,总有一个原因吧,就和爸妈给我们取名字一样总是寄予一些美好的期盼。

reducer的含义有很多,很多领域都用这个单词,但是在Redux中,这应该是函数式语言(functional languages)中的一个概念。在wiki中,通常称为Fold,作为一个结构转变(structural transformations)的一个方式。

其他语言Reducer实现方式我们不管,我们只看JS,在JS中出现的array.reduce(func,initval),相信大家应该很熟悉,也是一个刚上手就想哭的一个方法。数组中的reduce有什么特点呢(不会用reduce的小伙伴,点击这里):

  • 给出了一个初始initval
  • 有一个转换的func方法,这个方法必须是纯函数,既不改变传入对象的属性
  • 最终返回一个新的对象/值,而array保持不变。

从而可以推论出Redux中的reducer的特点:

  • 需要一个初始值,在redux中就是初始的state
  • 有一个转换的方法,这个方法必须是纯函数
  • 最终返回一个新的对象,也就是新的state,而传入的state保持不变。

大家可能对纯函数(pure funciton)有些模糊,函数还能pure??以为是纯牛奶呢??这里的pure的意思就是他是干干净净的,毫无杂质。也就是一下两点:

  • 不改变传入的state的属性,即不影响函数外的参数
  • 无副作用(side effect),比如触发了某个事件,或者捕获了什么值。也就是与外界绝缘,我就守好我的二亩三分地就好了。

大家想深入了解的话,双手奉上wiki链接

那么我们该怎么写呢?

大家复习下上面的action,reducer可是action配套的好兄弟,一个在前,一个在后并肩作战。

reducer并不是主动执行,而是被动执行的,来了一个action,然后reducer处理下。

简而言之:reducer就是响应来自action的召唤,然后返回一个新的对象(state)。

首先先导入来自action的行为,这行为是被注册的,是可以执行的。

const {TOGGLE_TODO,GET_TODOS}=require('../actions/Todo')

reducer的一个定义就是一定有个初始值,这里设置一个也就是以防万一。

const initialState={}

重点来了,reducer开始过滤注册的行为们,然后每次都是一个个配对,遇上配对的,就执行对应的代码,然后返回一个新的state,如果轮了一边发现这是未注册的行为,为了防止这个行为回去不好交代,就把原始的state给他带回去交差。

module.exports=function(state = initialState, action) {
switch(action.type){
case GET_TODOS:
return {todos:[...action.items]}
case TOGGLE_TODO://deleted=true
return {
todos:action.items.map((i)=>{
if(i.id===action.id){
return {
...i,
status:i.status===0?1:0
}
}else{
return {
...i
}
}
})
}
default:
return state;
}
}

reducer根据action的指令,进行一系列操作,但是不改变原有的传入对象(state),而是返回一个新的对象(state)。也就是Reducer,进行纯计算,没有异步,没有污染,出来的值没有意外,就像1+1一定等于2一样,然后返回一个崭新崭新的对象(state)!

拜见老大store

虽action和reducer是一对基,配合默契,但是他们都是两个独立的模块,怎么酱他们链接起来,还需要一个桥梁。这个就是store,redux中真正的老大,大家都要通过store来执行下一步的人任务,以及要听从store派发下来的任务。

我们先配置一个老大吧,todoDemoList是假数据,大家懂的测试用。老大只需要reducers这群小弟来建帮派createStore。action再帮派建立之初并无用处。

const {createStore}= require('../../node_modules/redux')
const todo = require('./reducers/Todo')
const {toggleTodo,getTodos} = require('./actions/Todo') let todoDemoList=(new Array(20)).join("|").split("|").map((v,i)=>{
return {id:i,content:"demo"+(i+1),status:i%4===0?1:0}
}) const store=createStore(todo)

我们的store究有何种能立呢?

  • 掌控整个应用的数据state,老大当然是掌控全局的啦,没有什么能瞒住他

  • 如果想要访问应用数据state,那么就要给store提申请,这个申请就是getState()

console.log(store.getState())//打印出来是一个空的{},当然啦!我们都没有给老大进贡,拿来的数据
  • 想要修改数据,那更要给老大提申请了,那就是dispatch(你的申请action)。action终于出场啦!
store.dispatch(getTodos({items:todoDemoList}))//给老大进贡
console.log(store.getState().todos[1])//有数据了
store.dispatch(toggleTodo({items:todoDemoList,id:1}))//修改某一个小罗罗
console.log(store.getState().todos[1])//修改成功
  • 不要以为你修改的时候可以为所欲为,老大看着呢。老大通过subscribe(监视器listener)看着你呢,小样给我注意点。不过此刻要注意,我们要把监听器放在所有的dispatch执行之前,不然就捕捉不到dispatch了。要在一切还没发生之前,就准备好,不然就要给小样们钻空子了。就像盗窃一样,小偷已经偷完跑路了,你再装监控,也逮不住这个小偷啊。
store.subscribe(()=>{
console.log(store.getState())//监控这手下的一举一动
})
  • 老大也不是不近人情之辈,如果说你的表现够好,还是会撤销监视的。这个撤销的方法就是store.subscribe()的返回值,这个返回值是一个方法,就像这样store.subscribe()()
let unsubscribe=store.subscribe(()=>{
console.log(store.getState())//监控这手下的一举一动
})
store.dispatch(toggleTodo({items:todoDemoList,id:1}))//老大在watching,小心翼翼。
unsubscribe()//放了你们,出去浪吧
store.dispatch(toggleTodo({items:todoDemoList,id:1}))//居然真的没有再继续监视我了,放飞自我。

老大怎么可能只有一个小弟reducer呢?当然有很多啦!combineReducers(小弟们)

一个帮派只能有一个老大!但是可以有很有小弟,每个小弟各司其职。但是要将这些小弟统一管理起来,这个时候就要用combineReducers了。

用相同的方法创建一个filterAction,然后用combineReducers一下,接下来就可以愉快地合作了。

...
const filterAction = require('./reducers/filterAction')
const {showCompleted} = require('./actions/filterAction')
...
const rootReducer = combineReducers({todo: todo, filterAction: filterAction})
....
store.dispatch(showCompleted({items:todoDemoList}))//success执行啦!

通俗易懂的Redux了解下的更多相关文章

  1. 第3章 从Flux到Redux

    第3章 从Flux到Redux 3.1 Flux 单向数据流,React是用来替换Jquery的,Flux是以替换Backbone.js.Ember.js等MVC框架为主的. actionTypes. ...

  2. 关于redux和react-redux使用combinereducers之后的问题

    最近用react写项目的时候,开始复习之前学过的redux,记录一下一些坑,以防忘记 我现在的redux目录下有这么些东西 首先是index.js import { createStore } fro ...

  3. Spark shuffle详细过程

    有许多场景下,我们需要进行跨服务器的数据整合,比如两个表之间,通过Id进行join操作,你必须确保所有具有相同id的数据整合到相同的块文件中.那么我们先说一下mapreduce的shuffle过程. ...

  4. JAVA bio nio aio

    [转自]http://qindongliang.iteye.com/blog/2018539 在高性能的IO体系设计中,有几个名词概念常常会使我们感到迷惑不解.具体如下: 序号 问题 1 什么是同步? ...

  5. MongoDB笔记(一)MongoDB概述和安装

    概述 关键词:关系数据库.非关系数据库 关系数据库: 关系数据库,是建立在关系数据库模型基础上的数据库,借助于集合代数等概念和方法来处理数据库中的数据.目前主流的关系数据库有oracle.SQL.ac ...

  6. JAVA 中BIO,NIO,AIO的理解以及 同步 异步 阻塞 非阻塞

    在高性能的IO体系设计中,有几个名词概念常常会使我们感到迷惑不解.具体如下: 序号 问题 1 什么是同步? 2 什么是异步? 3 什么是阻塞? 4 什么是非阻塞? 5 什么是同步阻塞? 6 什么是同步 ...

  7. 快速了解react

    概况: 通过本篇文章你可以对react的重点有个整体的认识. 关于react是什么,优点,解决什么问题等,网上一大推就不啰嗦了. 了解虚拟DOM的实现,参考这篇文章 [虚拟DOM](https://w ...

  8. React从入门到放弃之前奏(2):React简介

    本系列将尽可能使用ES6(ES2015)语法.所以均在上节webpack的基础上做开发. React是Facebook开发的一款JS库,因为基于Virtual DOM,所以响应速度快,以及支持跨平台. ...

  9. 前端异步技术之Promise

    前言 从事前端的朋友或多或少的接触过Promise,当代码中回调函数层级过多你就会发现Promise异步编程的魅力,相信此文一定能帮你排忧解惑! Promise概念 Promise是JS异步编程中的重 ...

随机推荐

  1. STM32:获取复位源,软件复位

    RCC CSR寄存器会存储复位标示,可通过它来知道复位原因,来源: if(RCC_GetFlagStatus(RCC_FLAG_PINRST)) printf("PINRST\r\n&quo ...

  2. Pascal约瑟夫问题

    program Project2; {$APPTYPE CONSOLE} const n=; m=; Type peopleno= ..n] of integer; var datering:peop ...

  3. hdu 1071 The area【定积分】

    用顶点式\( a(x-h)^2+k=y \)解方程,转化为\(ax^2+bx+c=y \)的形式,然后对二次函数求定积分\( \frac{ax^3}{3}+\frac{bx^2}{2}+cx+C \) ...

  4. 'ALTER TABLE SWITCH' 语句失败。表'MGXXX.dbo.user_XXX' 已分区,但 索引'ix_user_XXX_user_id' 未分区。

    问题描述: 今天在做分区切换的时候把旧log数据切到clear表,遇到了这个问题,顺便做下笔记记录一下解决方法 'ALTER TABLE SWITCH' 语句失败.表'MGXXX.dbo.user_X ...

  5. 【原创】《从0开始学Elasticsearch》—初识Elasticsearch

    目录 1. Elasticsearch 是什么2. Elasticsearch 中基本概念3. Elasticsearch 安装4. 访问 Elasticsearch 1. Elasticsearch ...

  6. [CF997E] Good SubSegment

    Description Transmission Gate 给你一个长度为n的排列P,定义一段子区间是好的,当且仅当这个子区间内的值构成了连续的一段.例如对于排列\(\{1,3,2\}\),\([1, ...

  7. [HNOI2008]Card洗牌

    Description 小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红 ...

  8. Windows软件推荐

    本篇博文主要记录一些实用性的windows软件或者插件,重在积累! 工具类 1.截图软件 https://zh.snipaste.com/ Snipaste 是一个简单但强大的截图工具,也可以让你将截 ...

  9. magento getMessage 不显示或者显示html标签解决方案

    在模板页面不显示getMessage的解决方案是,在对应的控制器里加上如下代码: $this->_initLayoutMessages('customer/session'); 如果加入后出现如 ...

  10. [完美方案+无懈可击]ubuntu 14.04(LTS) + GTX 980Ti显卡配置

    安装好系统之后出现的问题: 1 不能上网:后来通过删除链接新建一个以太网链接(自动DHCP)重启莫名其妙就好使了. 2 分辨率只有两个:1024x ? 和 800x600. 分辨率低到让人头痛.通过查 ...