Redux详解(一)

启示

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是怎么回事了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值