redux

教程

阮一峰教程
http://webcache.googleusercontent.com/search?q=cache:KY3E46PLHwQJ:www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html+&cd=10&hl=en&ct=clnk&gl=us

漫画教程
https://github.com/jasonslyvia/a-cartoon-intro-to-redux-cn

其余参考
https://www.w3ctech.com/topic/1561
https://segmentfault.com/a/1190000011474522

学习

Redux是一个状态管理框架,可以和很多现有的web技术结合使用,比如之前的react。

关键概念:

store: 保存状态
action(action creator): 保存操作
dispatch: 传递动作
reducer: 更新状态

Store 把它们联系到一起,Store 有以下职责:
维持应用的 state;
getState() 方法获取 state;
dispatch(action) 方法更新 state;
subscribe(listener) 注册监听器。

基本思路:

create a Redux store create actions and action creators dispatch your actions against the store update state with pure reducers

Store是Redux中唯一的一个state object,称为redux store,用来管理整个app的状态。

Action 实质上是一个js object,里面包含action event相关信息;

Action creator实质是一个返回action 的 js function,

Redux store接收到action后,使用reducer来相应更新状态

reducer实质是一个js function,接收state, action作为参数,返回一个新的state。

State可以为各种数据类型,number, string, array, object等等。
通常将action type定义为const类型值。
Reducer中常用的模式是使用switch, case,根据action 的type属性来进行相应的更新状态操作。

注意
Immutable state means that you never modify state directly, instead, you return a new copy of state。
也即state应该是一个不变化的值,对于基础数据类型本来就是不变的,所以不用特殊处理,而对于复杂数据类型,比如object, array,需要首先进行深度复制取得state的副本,然后对副本进行处理。

how to manage complex state with reducer composition ,复杂state时组合reducer handle asynchronous actions:异步处理

使用

  1. 常用代码模块:

const currentState = store.getState();


- create action,action creator and dispatch: 

const action = { type: ‘LOGIN’ } const actionCreator = function(){ return action; }

store.dispatch(actionCreator()); store.dispatch(action);


- 完整示例一:

//define constant for action types const INCREMENT = ‘INCREMENT’; const DECREMENT = ‘DECREMENT’;

//define action creator to return action const incAction = function(){ return{ type:INCREMENT } };

const decAction = function(){ return{ type: DECREMENT } };

//define reducer with action as parameter const counterReducer = (state=0, action) => { switch(action.type) { case INCREMENT: return state + 1; case DECREMENT: return state - 1; default: return state; } };

// define the Redux store here, passing in your reducers const store = Redux.createStore(counterReducer);

- 完整示例二:

//action type const LOGIN = ‘LOGIN’; const LOGOUT = ‘LOGOUT’;

const defaultState = { authenticated: false };

//action creator, return aciton const loginUser = () => { return { type: LOGIN } }; const logoutUser = () => { return { type: LOGOUT } };

//reducer const authReducer = (state = defaultState, action) => {

switch (action.type) {

case LOGIN:
  return {
    authenticated: true
  }

case LOGOUT:
  return {
    authenticated: false
  }

default:
  return state;   }

};

//store const store = Redux.createStore(authReducer);


2. store.subscribe()的使用  
为store注册处理函数event listener

示例代码:

const ADD = ‘ADD’; let count = 0;

function add(){ count++; }

const reducer = (state = 0, action) => { switch(action.type) { case ADD: return state + 1; default: return state; } };

const store = Redux.createStore(reducer);

store.subscribe(add); store.dispatch({type: ADD}); console.log(count); store.dispatch({type: ADD}); console.log(count); store.dispatch({type: ADD}); console.log(count);



3. 复杂state处理  
当state变得复杂时,可能想将它分为几个模块,但是因为redux只能有一个state store来保存状态,因此不可以有多个store,但是却可以使用多个reducer针对state的每个模块分别进行处理,最后再将这些reducer组合起来。  
为了实现这种功能,redux提供了 combineReducers() method

完整示例代码:

const INCREMENT = ‘INCREMENT’; const DECREMENT = ‘DECREMENT’;

const defaultState = { count: 0, auth: {authenticated: false} };

const inAction = function(){ return{ type: INCREMENT } }; const deAction = function(){ return{ type: DECREMENT } };

const counterReducer = (state = defaultState.count, action) => { switch(action.type) { case INCREMENT: return state + 1; case DECREMENT: return state - 1; default: return state; } };

const LOGIN = ‘LOGIN’; const LOGOUT = ‘LOGOUT’;

const loginAction = function(){ return{ type: LOGIN } }; const logoutAction = function(){ return{ type: LOGOUT } };

const authReducer = (state = defaultState.auth, action) => { switch(action.type) { case LOGIN: return { authenticated: true } case LOGOUT: return { authenticated: false } default: return state; } };

const rootReducer = Redux.combineReducers({ auth: authReducer, count: counterReducer });

const store = Redux.createStore(rootReducer);



4. state 的不变性  
state的不变性,在redux中是一个非常重要的概念。
而且,这个需要编程人员自己来维护。
如果state为number, or string等基本数据类型,那么本身就是具有不变性的,所以不需要特别处理,但是当为 array[] or object时,就要特别注意了,需要首先进行深度复制取得state的副本,然后对副本进行处理。

**Array时的immutable实现**  

其实实质就是如何复制array:  
可以使用concat, slice, …等;  

One solution from ES6 to help enforce state immutability in Redux is the spread operator: …

let newArray = […myArray];

newArray is now a clone of myArray. Both arrays still exist separately in memory. If you perform a mutation like newArray.push(5), myArray doesn’t change. The … effectively spreads out the values in myArray into a new array.

To clone an array but add additional values in the new array, you could write […myArray, ‘new value’]. This would return a new array composed of the values in myArray and the string ‘new value’ as the last value. The spread syntax can be used multiple times in array composition like this, but it’s important to note that it only makes a shallow copy of the array. That is to say, it only provides immutable array operations for one-dimensional arrays.


示例一: const ADD_TO_DO = ‘ADD_TO_DO’; // A list of strings representing tasks to do: const todos = [ ‘Go to the store’, ‘Clean the house’, ‘Cook dinner’, ‘Learn to code’, ];

const immutableReducer = (state = todos, action) => { switch(action.type) { case ADD_TO_DO: // don’t mutate state here or the tests will fail const rlt = state.slice(0); rlt.push(action.todo); return rlt; //return state.concat(action.todo); //return […state,action.todo]; default: return state; } };

// an example todo argument would be ‘Learn React’, const addToDo = (todo) => { return { type: ADD_TO_DO, todo } }

const store = Redux.createStore(immutableReducer);

示例二: const immutableReducer = (state = [0,1,2,3,4,5], action) => { switch(action.type) { case ‘REMOVE_ITEM’: const s = state.slice(0,action.index); const e = state.slice(action.index+1); return s.concat(e); default: return state; } };

const removeItem = (index) => { return { type: ‘REMOVE_ITEM’, index } }

const store = Redux.createStore(immutableReducer);


**object时的immutable实现**  

实质就是如何对object进行深复制  
可以使用 Object.assign()来实现。

A useful tool for handling objects is the Object.assign() utility.

Object.assign() takes a target object and source objects and maps properties from the source objects to the target object. Any matching properties are overwritten by properties in the source objects. This behavior is commonly used to make shallow copies of objects by passing an empty object as the first argument followed by the object(s) you want to copy.

Here’s an example: const newObject = Object.assign({}, obj1, obj2); This creates newObject as a new object, which contains the properties that currently exist in obj1 and obj2.

示例: const defaultState = { user: ‘CamperBot’, status: ‘offline’, friends: ‘732,982’, community: ‘freeCodeCamp’ };

const immutableReducer = (state = defaultState, action) => { switch(action.type) { case ‘ONLINE’: return Object.assign({}, state,{status: ‘online’}); default: return state; } };

const wakeUp = () => { return { type: ‘ONLINE’ } };

const store = Redux.createStore(immutableReducer); ~~~