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 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对象的映射关系

// 容器组件的代码
//    <FilterLink filter="SHOW_ALL">
//      All
//    </FilterLink>

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. <Provider>组件:React-Redux提供,让容器组件拿到state

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

学习自:

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容