Redux, React-Redux

Redux: JavaScript 状态容器,提供可预测化的状态管理

需要使用Redux 的情景:

  1. 用户的使用方式复杂
  1. 不同身份的用户有不同的使用方式(比如普通用户和管理员)
  2. 多个用户之间可以协作
  3. 与服务器大量交互,或者使用了WebSocket
  4. View要从多个来源获取数据
  5. 某个组件的状态,需要共享
  6. 某个状态需要在任何地方都可以拿到
  7. 一个组件需要改变全局状态
  8. 一个组件需要改变另一个组件的状态

Redux设计思想:

(1)Web 应用是一个状态机,视图与状态是一一对应的。
(2)所有的状态,保存在一个对象里面。

API:

*1. Store容器:保存所有数据,整个应用只能有一个Store

const store = createStore(fn, window.STATE_FROM_SERVER); 
//接受另一个函数作为参数,生成返回新的Store对象。第二个参数通常是服务器给出,表示整个应用的初始状态值,会覆盖Reducer函数的默认初始值

*2. State对象:Store快照,某一时间点的数据集合,(规定State和View唯一对应,知其一就可推断另一个)
const state = store.getState(); //拿到当前时刻的State

*3. Action对象:描述当前发生的事情,用户改变界面后,改变State的唯一办法,Action会运送数据到Store

const action = {
  type: 'ADD_TODO', //必须,表示Action名称
  payload: 'learn redux'  //携带的信息
}

*4. Action Creator函数:生成Action,解决多个View手动生成多个Action的麻烦

const ADD_TODO = 'add TODO';
function addTodo(text) {  //Action Creator
  return {
    type: ADD_TODO,
    text
  }
}
const action = addTodo('learn');

*5. store.dispatch():View发出Action的唯一方法

import { createStore } from 'redux';
const store = createStore(fn);
store.dispatch({  //将Action对象作为参数发送出去
  type: 'ADD_TODO',
  payload: 'learn'
}); //可以是: store.dispatch(action);结合Action Creator

*6. Reducer函数:Store 收到Action后,须给出新的State来改变View,新State 的计算过程就是Reducer

const defaultState = 0;
const reducer = (state = defaultState, action) => { //接受旧State和收到的antion作为参数
  switch (action.type) {
    case 'ADD':
      return state + action.payload;  //返回新的State
    default:
      return state;
  }
}
//手动调用
const state = reducer(1, action);
//自动调用
import { createStore } from 'redux';
const store = createStore(reducer); //每当store.dispatch() 发送一个新的Action ,就会自动调用 reducer()

*7. 纯函数:同样的输入,必定得到同样的输出,有约束:

  • 不得改写参数
  • 不能调用系统 I/O 的API
  • 不能调用Date.now() 或者Math.random()等不纯的方法,每次会得到不一样的结果
//保证返回的是新对象或数组,不改变之前的State,使得某个State与某个View仍然唯一对应
function reducer(state, action) {
  return Object.assign({}, state, { change });  // or return {...state, ...newState},State是对象

  return [...state, newItem]; //State是数组
}

*8. store.subscribe(): 监听State的变化
store.subscribe(listener); //listener可以是React的render(), setState()方法,即可实现View 的自动渲染
let unsubscribe = store.subscribe(listener);unsubscribe();//即可解除监听

*9. combineReducers(): 合并子Reducer()成一个大的函数

/*
 *假设:三种Action 分别改变State 的三个属性
 *- ADD_C:c属性
 *- CHANGE_S:s属性
 *- CHANGE_U:u属性
 */
const chatReducers = (state = defaultState, action = {}) => {  //为了避免庞大的State导致复杂的Reducer,所以Reducer的拆分
  return {  //各个子Reducer 函数均是自定义
    c: c(state.c, action),
    s: s(state.s, action),
    u: u(state.u, action)
  }
}
/*前提:State 属性名必须与子 Reducer 同名*/
import { combineReducers } from 'redux';
const chatReducer = combineReducers({ //合并上面对 Reducer 的拆分
  c,
  s,
  u
})

Redux工作流程

Redux, React-Redux_第1张图片
Redux Flow

中间件(middleware):为实现Reducer异步操作

*1. applyMiddlewares(): 将所有中间件组成一个数组,依次执行,所以加载时,需要查询中间件的执行顺序

*2. 异步操作:

//三种Action(发起时,成功时,失败时)
// 写法一:名称相同,参数不同
{ type: 'FETCH_POSTS' }
{ type: 'FETCH_POSTS', status: 'error', error: 'Oops' }
{ type: 'FETCH_POSTS', status: 'success', response: { ... } }

// 写法二:名称不同
{ type: 'FETCH_POSTS_REQUEST' }
{ type: 'FETCH_POSTS_FAILURE', error: 'Oops' }
{ type: 'FETCH_POSTS_SUCCESS', response: { ... } }
//State三种属性
let state = {
  isFetching: true,//是否抓取数据
  didInvalidate: true,//数据是否过时
  lastUpdated: 'xxxxxxx'//上一次更新时间
};

思路:操作开始时,送出一个 Action,触发 State 更新为"正在操作"状态,View 重新渲染;操作结束后,再送出一个 Action,触发 State 更新为"操作结束"状态,View 再一次重新渲染

*3. redux-thunk中间件:异步操作,写出一个返回函数的 Action Creator,然后设applyMiddlewares为redux-thunk中间件改造store.dispatch,使其可接受函数参数

*4. redux-promise中间件: 异步操作,让Action Creator 返回一个Promise对象,设applyMiddlewares为redux-promise

React-Redux: 将所有组件分成两大类(UI组件和容器组件)

React-Redux 规定,所有的 UI 组件都由用户提供,容器组件则是由 React-Redux 自动生成。也就是说,用户负责视觉层,状态管理则是全部交给它。

*1. UI组件:只负责 UI 的呈现,不带有任何业务逻辑;没有状态(即不使用this.state这个变量);所有数据都由参数(this.props)提供;不使用任何 Redux 的 API

*2. 容器组件:负责管理数据和业务逻辑,不负责 UI 的呈现;有内部状态;使用 Redux 的 API

*3. connect(): React-Redux提供,用于从UI组件生成容器组件,两组件建立联系

const VisibleTodoList = connect(
  mapStateToProps,  //输入逻辑:外部的数据(state)如何转换为UI组件的参数
  mapDispatchToProps  //输出逻辑:用户发出的动作如何变为Action对象,从UI组件传出去
  )(TodoList);//TodoList是UI组件,由此生成了容器组件

*4. mapStateToProps(): 建立一个从(外部的)state对象到(UI 组件的)props对象的映射关系

// 容器组件的代码
//    
//      All
//    

const mapStateToProps = (state, ownProps) => {  //参数1:state对象,参数2:容器组建的props对象
  return {
    active: ownProps.filter === state.visibilityFilter
  }
}

*5. mapDispatchToProps: 定义了哪些用户的操作应该当作 Action,传给 Store,可以是函数或者对象

//函数
const mapDispatchToProps = (dispatch,ownProps) => {
  return {
    onClick: () => {
      dispatch({
        type: 'SET_VISIBILITY_FILTER',
        filter: ownProps.filter
      });
    }
  };
}
//对象
const mapDispatchToProps = {
  onClick: (filter) => {
    type: 'SET_VISIBILITY_FILTER',
    filter: filter
  };
}

*6. 组件:React-Redux提供,让容器组件拿到state

ReactDOM.render(
    //let store = createStore(reducer); Redux生成store对象
     //在跟组件外包一层,则其所有子组件就默认都能拿到state了
  ,
  document.getElementById('root')
)

学习自:

Redux 入门教程(一):基本用法
Redux 入门教程(二):中间件与异步操作
Redux 入门教程(三):React-Redux 的用法

你可能感兴趣的:(Redux, React-Redux)