Redux系列01+核心概念 工作流程 安装 Action和Action创建函数 Reducer Store 数据流

来源:互联网 发布:未网络上注册 有信号 编辑:程序博客网 时间:2024/05/20 03:07

转载请注明预见才能遇见的博客:http://my.csdn.net/

原文地址:http://blog.csdn.net/pcaxb/article/details/68929943

Redux系列01+核心概念 工作流程 安装 Action和Action创建函数 Reducer Store 数据流

Redux 本身很简单。Redux 是 JavaScript 状态容器,提供可预测化的状态管理。当使用普通对象来描述应用的 state 时,这个对象就像 “Model”,区别是它并没有 setter(修改器方法)。因此其它的代码不能随意修复它,造成难以复现的 bug。要想更新 state 中的数据,你需要发起一个 action。Action 就是一个普通 JavaScript 对象用来描述发生了什么。

强制使用 action 来描述所有变化带来的好处是可以清晰地知道应用中到底发生了什么。如果一些东西改变了,就可以知道为什么变。action 就像是描述发生了什么的面包屑。最终,为了把 action 和 state 串起来,开发一些函数,这就是 reducer。再次地,没有任何魔法,reducer 只是一个接收 state 和 action,并返回新的 state 的函数。 对于大的应用来说,可能很难开发这样的函数,所以我们编写很多小函数来分别管理 state 的一部分。

1.三大原则
(1)单一数据源

整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。这让同构应用开发变得非常容易。来自服务端的 state 可以在无需编写更多代码的情况下被序列化并注入到客户端中。由于是单一的 state tree ,调试也变得非常容易。在开发中,你可以把应用的 state 保存在本地,从而加快开发速度。此外,受益于单一的 state tree ,以前难以实现的如“撤销/重做”这类功能也变得轻而易举。
(2)State 是只读的
惟一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。
这样确保了视图和网络请求都不能直接修改 state,相反它们只能表达想要修改的意图。因为所有的修改都被集中化处理,且严格按照一个接一个的顺序执行,因此不用担心 race condition 的出现。 Action 就是普通对象而已,因此它们可以被日志打印、序列化、储存、后期调试或测试时回放出来。
(3)使用纯函数来执行修改
为了描述 action 如何改变 state tree ,你需要编写 reducers。
Reducer 只是一些纯函数,它接收先前的 state 和 action,并返回新的 state。刚开始你可以只有一个 reducer,随着应用变大,你可以把它拆成多个小的 reducers,分别独立地操作 state tree 的不同部分,因为 reducer 只是函数,你可以控制它们被调用的顺序,传入附加数据,甚至编写可复用的 reducer 来处理一些通用任务,如分页器。

2.工作流程


(1)用户发出 Action
store.dispatch(action);
(2)Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action。 Reducer 会返回新的 State 。
let nextState = todoApp(previousState, action);
(3)State 一旦有变化,Store 就会调用监听函数。
// 设置监听函数store.subscribe(listener);
listener可以通过store.getState()得到当前状态。如果使用的是 React,这时可以触发重新渲染 View。
function listerner() {  let newState = store.getState();  component.setState(newState);}

3.安装
安装redux稳定版
npm install --save redux
安装附加包
npm install --save react-reduxnpm install --save-dev redux-devtools
安装中间件
npm install --save redux-loggernpm install --save redux-thunknpm install --save redux-promise


4.Action和Action创建函数

Action 是把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。
const ADD_TODO = 'ADD_TODO';{type:ADD_TODO,payload:'data'}
Action 本质上是 JavaScript 普通对象。我们约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作。多数情况下,type 会被定义成字符串常量。当应用规模越来越大时,建议使用单独的模块或文件来存放 action。
减少样板代码:减少样板代码  Flux 标准 Action:Flux 标准 Action
Action 创建函数 就是生成 action 的方法。“action” 和 “action 创建函数” 这两个概念很容易混在一起,使用时最好注意区分。在 Redux 中的 action 创建函数只是简单的返回一个 action:(这样做将使 action 创建函数更容易被移植和测试)
export function addTodo(payload){    return {type:ADD_TODO,payload:payload};}
store 里能直接通过 store.dispatch() 调用 dispatch() 方法,但是多数情况下你会使用 react-redux 提供的 connect() 帮助器来调用。bindActionCreators() 可以自动把多个 action 创建函数 绑定到 dispatch() 方法上。Action 创建函数也可以是异步非纯函数。你可以通过学习异步 action知识,学习如何处理 AJAX 响应和如何把 action 创建函数组合进异步控制流。

5.Reducer
Action 只是描述了有事情发生了这一事实,并没有指明应用如何更新 state。而这正是 reducer 要做的事情。reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。
(previousState, action) => newState
开发复杂的应用时,不可避免会有一些数据相互引用。建议你尽可能地把 state 范式化,不存在嵌套。把所有数据放到一个对象里,每个数据以 ID 为主键,不同实体或列表间通过 ID 相互引用数据。把应用的 state 想像成数据库。这种方法在normalizr文档里有详细阐述。
之所以称作 reducer 是因为它将被传递给 Array.prototype.reduce(reducer, ?initialValue) 方法。保持 reducer 纯净非常重要。永远不要在 reducer 里做这些操作:
(1)修改传入参数;
(2)执行有副作用的操作,如 API 请求和路由跳转;
(3)调用非纯函数,如 Date.now() 或 Math.random()

现在只需要谨记 reducer 一定要保持纯净。只要传入参数相同,返回计算得到的下一个 state 就一定相同。没有特殊情况、没有副作用,没有 API 请求、没有变量修改,单纯执行计算。
export function addToDoReducer(state={datas:[]},action){    switch(action.type){        case ADD_TODO:            state.datas.push({text:action.payload});            return Object.assign({},state);        default:            return state;    }}
说明:
(1)不直接修改 state 中的字段,而是返回新对象。使用 Object.assign() 新建了一个副本。不能这样使用 Object.assign(state, { visibilityFilter: action.filter }),因为它会改变第一个参数的值。你必须把第一个参数设置为空对象。你也可以开启对ES7提案对象展开运算符的支持, 从而使用 { ...state, ...newState } 达到相同的目的。
(2)在 default 情况下返回旧的 state。遇到未知的 action 时,一定要返回旧的 state。

我们需要修改数组中指定的数据项而又不希望导致突变, 因此我们的做法是在创建一个新的数组后, 将那些无需修改的项原封不动移入, 接着对需修改的项用新生成的对象替换。如果经常需要这类的操作,可以选择使用帮助类 React-addons-update,updeep,或者使用原生支持深度更新的库 Immutable。最后,时刻谨记永远不要在克隆 state 前修改它。

6.Store
Store 就是把它们联系到一起的对象。Store 有以下职责:
(1)维持应用的 state;
(2)提供 getState() 方法获取 state;
(3)提供 dispatch(action) 方法更新 state;
(4)通过 subscribe(listener) 注册监听器;
(5)通过 subscribe(listener) 返回的函数注销监听器

再次强调一下 Redux 应用只有一个单一的 store。当需要拆分数据处理逻辑时,你应该使用 reducer 组合 而不是创建多个 store。
根据已有的 reducer 来创建 store 是非常容易的。
let store = createStore(todoApp)
createStore() 的第二个参数是可选的, 用于设置 state 初始状态。这对开发同构应用时非常有用,服务器端 redux 应用的 state 结构可以与客户端保持一致, 那么客户端可以将从网络接收到的服务端 state 直接用于本地数据初始化。
let store = createStore(todoApp, window.STATE_FROM_SERVER)


7.数据流

严格的单向数据流是 Redux 架构的设计核心。这意味着应用中所有的数据都遵循相同的生命周期,这样可以让应用变得更加可预测且容易理解。同时也鼓励做数据范式化,这样可以避免使用多个且独立的无法相互引用的重复数据。
Redux 应用中数据的生命周期遵循下面 4 个步骤:
(1)调用 store.dispatch(action)
。你可以在任何地方调用 store.dispatch(action),包括组件中、XHR 回调中、甚至定时器中。
dispatch分发 action,用来修改store的状态。这是触发 state 变化的惟一途径。
(2)store 调用传入的 reducer 函数。Store 会把两个参数传入 reducer: 当前的 state 树和 action。注意 reducer 是纯函数。它仅仅用于计算下一个 state。它应该是完全可预测的:多次传入相同的输入必须产生相同的输出。它不应做有副作用的操作,如 API 调用或路由跳转。这些应该在 dispatch action 前发生。
(3)根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树。根 reducer 的结构完全由你决定。Redux 原生提供combineReducers()辅助函数,来把根 reducer 拆分成多个函数,用于分别处理 state 树的一个分支。

(4)store 保存了根 reducer 返回的完整 state 树。这个新的树就是应用的下一个 state!所有订阅 store.subscribe(listener) 的监听器都将被调用;监听器里可以调用 store.getState() 获得当前 state。现在,可以应用新的 state 来更新 UI。如果你使用了 React Redux 这类的绑定库,这时就应该调用 component.setState(newState) 来更新。

Actions.js

export const ADD_TODO = 'ADD_TODO';export function addTodoAction(payload){    return {type:ADD_TODO,payload:payload};}
Reducers.js

import {ADD_TODO} from '../action/Actions'export function addToDoReducer(state={datas:[]},action){    switch(action.type){        case ADD_TODO:            state.datas.push({text:action.payload});            return Object.assign({},state);        default:            return state;    }}
Index.js

import React,{Component} from 'react';import {render} from 'react-dom';import {Provider,crea} from 'react-redux';import {createStore} from 'redux';//Actionsimport {addTodoAction} from './action/Actions'//Reducersimport {addToDoReducer} from './reducer/Reducers'//storelet store = createStore(addToDoReducer);const Index = React.createClass({    getInitialState(){        //console.log(store.getState());        return {            datas:store.getState()        }    },    componentDidMount() {        //监听store的状态变化        let unsubscribe = store.subscribe(this.onChange);    },    onChange(){        this.setState({            datas:store.getState()        });    },    toAdd(){        let input = this.refs.input;        let value = input.value;        if(value){            store.dispatch(addTodoAction(value));            input.value = '';        }    },    render(){        return (<div>            <input ref="input"/><button onClick={this.toAdd}>添加</button>            <ul>            {                this.state.datas.datas.map(function(data,index){                    return <li key={index}>{data.text}</li>                })            }            </ul>        </div>);    }})render(<Index/>,document.getElementById('content'));

Redux系列01+核心概念 工作流程 安装 Action和Action创建函数 Reducer Store 数据流

博客地址:http://blog.csdn.net/pcaxb/article/details/68929943




0 0
原创粉丝点击