Redux详解(一)

翻译 2016年05月30日 12:14:00

启示

Redux由Flux演变而来,但受Elm的启发,避开了Flux的复杂性。
不管你有没有使用过他们,只需几分钟就能上手Redux。

安装

安装稳定版:

npm install --save redux

多数情况下,你还需要使用React绑定库和开发者工具

npm install --save react-redux
npm install --save-dev redux-devtools

要点

应用中所有的state都以一个对象数的形式储存在一个单一的store中。
唯一改变state的办法是触发action,一个描述发生什么的对象。
为了描述action如何改变state树,你需要编写reducers。
就是这样:

/**
 * Created by iqianjin-shisong on 16/5/30.
 */
import { createStore } from 'redux';

/**
 * 这是一个 reducer,形式为 (state, action) => state 的纯函数.
 * 描述了 action 如何把state转变成下一个 state.
 * 
 * state 的形式取决于你, 可以使基本类型,数组,对象
 * 甚至是 Immutable.js 生成的数据结构. 唯一的要点是
 * 当state变化时需要返回全新的对象,而不是修改传入的参数.
 * 
 * 下面的例子使用 'switch' 语句和字符串来做判断, 但你可以写帮助类(helper)
 * 根据不同的约定(如方法映射)来做判断,只要使用你的项目即可
 * 
 * @param state
 * @param action
 * @returns {number}
 */
function counter(state = 0, action) {
    switch (action.type) {
        case 'INCREMENT':
            return state + 1;
        case 'DECREMENT':
            return state - 1;
        default:
            return state;
    }
}

// 来创建 Redux store 来存放应用的状态
// API 是 { subscribe, dispatch, getState }
let store = createStore(counter);

// 可以手动订阅更新, 也可以事件绑定到视图层
store.subscribe(() => 
    console.log(store.getState())
);

// 改变内部 state 唯一方法是 dispatch 一个 action
// action 可以本序列化, 用日记记录和储存下来,后期还可以以回放的方式执行
store.dispatch({type: 'INCREMENT'})
// 1
store.dispatch({type: 'INCREMENT'})
// 2
store.dispatch({type: 'DECREMENT'})
// 1

你应该把要做的修改变成一个普通对象,这个对象被叫做 action,而不是直接修改state。然后编写专门的函数来决定每个 action 如何改变应用的state, 这个函数被叫做 reducer。

如果你以前使用 Flux,那么你只需要注意一个重要的区别。 Redux 没有Dispatcher 且不支持多个store。相反,只有一个单一的store和一个根级的 reducer 函数。随着应用不断变大,你应该把根级的 reducer拆成多个小的reducer, 分别独立的操作 state 树的不同部分,而不是添加新的 stores。这就像一个 React 应用只有一个根级的组件,这个根组件又由很多小组件构成。
用这个架构开发计数器有点杀鸡用牛刀,但它的美在于做复杂应用和庞大系统时邮箱的扩展能力。由于它可以用action 追溯应用的每一次修改,因此才有强大的开发工具。如录制用户会话并回放所有action来重现它。

三大原则


Redux 可以用这三个基本原则来描述:

单一数据源

整个应用的 state 被储存在一颗 object tree 中, 并且这个 object tree 只存在于唯一一个 store 中。
这让同构应用开发变得飞航容易。来自服务端的 state 可以在无需编写更多代码的情况下被序列化并注入到客户端中。由于是单一的 state tree, 调试也变得非常容易。 在开发中, 你可以把应用的 state 保存在本地,从而加快开发速度。此外,受益于单一的 state tree ,以前难以实现的如“撤销/重做”这类功能也变得轻而易举。

console.log(store.getState());

{
  visibilityFilter: 'SHOW_ALL',
  todos: [{
    text: 'Consider using Redux',
    completed: true,
  }, {
    text: 'Keep all state in a single tree',
    completed: false
  }]
}

State是只读的

唯一改变 state 的方法就是触发 state, action 是一个用于描述已发生时间的普通对象。
这确保了视图和网络请求都不能直接修改state,相反他们只能表达想要修改的意图,因为所有的修改都被集中化处理,且严格按照一个接一个的顺序执行,因此不用担心 race condition 的出现。 Action 就是普通对象而已,因此他们可以被日志打印、序列化、储存、后期调试或测试时回放出来。

store.dispatch({
  type: 'COMPLETE_TODO',
  index: 1
});

store.dispatch({
  type: 'SET_VISIBILITY_FILTER',
  filter: 'SHOW_COMPLETED'
});

使用纯函数来执行修改

为了描述 action 如何改变 state tree, 你需要编写 reducers。
Reducer只是一些纯函数,他接受先前的 state 和 action,并返回新的 state。 刚开始你可以只有一个reducer, 随着应用变大,你可以把它拆成多个小的 reducers, 分别独立地操作 state tree 的不同部分,因为 reducer 只是函数,你可以控制他们被调用的顺序,传入附加数据,甚至编写可复用的 reducer 来处理一些通用任务,如分页器。


function visibilityFilter(state = 'SHOW_ALL', action) {
    switch (action.type) {
        case 'SET_VISIBILITY_FILTER':
            return action.filter;
        default:
            return state;
    }
}

function todos(state = [], actioin) {
    switch (actioin.type) {
        case 'ADD_TODO':
            return [...state, {
                text: actioin.text,
                completed: false
            }];
        case 'COMLETE_RODO':
            return [...state.slice(0, action.index),
                Object.assign({}, state[action.index], {
                    completed: true
                }),
                ...state.slice(action.index + 1)
            ];
        default:
            return state;
    }
}

import  { combineReducers, createStore } from 'redux';
let reducer = combineReducers({ visibilityFilter, todos });
let store = createStore(reducer);

就是这样,现在应该明白Redux是怎么回事了。

redux的reducer纯函数处理state的2种方法

1、使用lodash的_.cloneDeep()函数 深复制,可以递归复制复杂的对象,Object.assign()和_.assign()只会复制对象的第一层属性,更深层次的属性是引用赋值的,指向同...
  • wojiong132
  • wojiong132
  • 2017年04月02日 21:47
  • 467

前端学习总结(十九)Redux——管理state数据最优雅的解决方案

一 Redux简介Redux 是 JavaScript 状态容器,提供可预测化的状态管理动机与目的JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 stat...
  • haoshidai
  • haoshidai
  • 2016年08月16日 21:03
  • 7133

解决redux安装慢问题

redux安装慢问题: npm install -g nrm nrm use taobao 安装redux(进入到react项目工程根目录下)  npm install --save react ...
  • majiakun1
  • majiakun1
  • 2016年01月15日 17:00
  • 3079

Redux源码拾遗,关于createStore的第三个参数

简要介绍:再看redux文档的时候,发现了createStore是允许第三个参数的,看了一下源码明白了第三个参数的作用。一、createStore的第三个参数的定义(1)官方定义:createStor...
  • liwusen
  • liwusen
  • 2017年07月29日 19:04
  • 877

Redux 中 combineReducers 和 createStore的实现原理

最近一直在学习 redux, 感到了深深的难过,都两天了,感觉还是不知道怎么写代码,倒不是不知道是Redux 里面涉及的概念,是不知道什么代码该放在哪里。怎么样组织结构。希望再过两天能更清晰。 ...
  • u012798391
  • u012798391
  • 2016年10月26日 01:24
  • 2382

配置redux react 以及webpack

npm init npm install npm install webpack --save-dev npm install react npm install react-dom npm ins...
  • Phil_Young
  • Phil_Young
  • 2016年05月16日 16:56
  • 1434

react和redux中的几种常用的方法

1. createStore(reducer, [initState, enhancer])------redux中的方法 作用:创建一个Redux store来存放应用中所有的state,一个...
  • tangzhl
  • tangzhl
  • 2017年05月01日 15:11
  • 1238

react+redux框架配置从无到有直到正常运行全流程(下)

本文转载自 前端_Logic 的博文, 原文地址:http://blog.csdn.net/lx376693576/article/details/54602957 写于:2017-1-1...
  • dj513dj
  • dj513dj
  • 2017年02月21日 10:36
  • 2554

redux 及 react-redux基本用法及源码解析

某年某月某日,某师兄说:学一个东西,不能只停留在表面,只知道怎么用是完全不够的, 要清楚的明白,为什么这么做,为什么不那样做,还得从源码开始,虽然起步可能会比较坎坷,毕竟知识储备有限。 点到为止了,所...
  • luke_up
  • luke_up
  • 2017年01月12日 15:52
  • 982

为什么 react 中要使用 redux

背景作为一名后端工程师,我最近在学习前端 react 知识,准备转全栈工程师,学 react 势必要学习 redux ,初学 redux 的时候,觉得 redux 很鸡肋,根据我的经验来看,我认为 r...
  • u010632868
  • u010632868
  • 2017年07月11日 00:15
  • 475
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Redux详解(一)
举报原因:
原因补充:

(最多只允许输入30个字)