Ref: Redux中文文档

Ref: React 讀書會 - B團 - Level 19 Redux 深入淺出

Ref: React+Redux 分享會

Ruan Yifeng, Redux 架构: 教程一有代码)、教程二教程三

Redux 入门教程 #1 课程介绍

Redux 入门教程 #2 为什么需要 Redux

Redux 入门教程 #3 什么是 Redux

Redux 入门教程 #4 创建页面

Redux 入门教程 #5 单独使用 Redux

Redux 入门教程 #6 使用 react-redux

课前阅读


(1) 首先,复习 Flux[React] 07 - Flux: react communicates with mongodb

  • 原始方案中,pages目录下其实也是组件的效果;
  • 右边的flux pattern到底带来了什么?

详见Flux章节和链接。

     

(2) 之后,让我们开始对 Redux 认真学习。

2015年,Redux 出现,将 Flux 与函数式编程结合一起,很短时间内就成为了最热门的前端架构。

* 是什么?

  • actions
  • components
  • constants
  • reducers
  • store

管理数据的状态容器,单独的js库。

* 解决什么问题?

A如何把参数传给B?react的单向流不好处理。

或者,使用嵌入式写法,比如A触发事件,B监听事件。

但嵌入式写法不推荐。

  • React两大不利之处,
  • 代码结构
  • 组件之间的通信
  • 从需求角度看,
  • 用户的使用方式复杂
  • 不同身份的用户有不同的使用方式(比如普通用户和管理员)
  • 多个用户之间可以协作
  • 与服务器大量交互,或者使用了WebSocket
  • View要从多个来源获取数据
  • 从组件角度看,
  • 某个组件的状态,需要共享
  • 某个状态需要在任何地方都可以拿到
  • 一个组件需要改变全局状态
  • 一个组件需要改变另一个组件的状态

原理解剖


一、基本步骤

第一步,从老阮开始。设计一个如下的"加减计数器"。

[1] ----------------------------------------------------------------------------------------------------------------------------------------> Store & State

两个重要的功能:

(1)创建唯一的一个store。

(2)获取该store里面的state。

import { createStore } from 'redux';
const store = createStore(reducer);      // 1.接受另一个函数作为参数,返回新生成的 Store 对象
const state = store.getState(); // 2.得到当前时刻的State,一个state对应一个view

Jeff: 在flux中的state计算问题放在了reducer中,reducerstore通过createStore()维持关系。

[2] ----------------------------------------------------------------------------------------------------------------------------------------> Action

用户操作 on view --> action --> state

# 想要的结果

const action = {
type: 'ADD_TODO',          // Action的名称,是必须的;Action本身是个对象
payload: 'Learn Redux'         // Action的货物,不是必须的;
};

使用 Action Creator,避免全部“手写定义”带来的麻烦,返回以上的结果。

const ADD_TODO = '添加 TODO';

function addTodo(text) {
return {
type: ADD_TODO,
text
}
} const action = addTodo('Learn Redux');

[3] ----------------------------------------------------------------------------------------------------------------------------------------> store.dispatch()

通过store.dispatch (...),view 发出 action (参数) to store.

store.dispatch({
type : 'ADD_TODO',
payload: 'Learn Redux'
}); 或者,对象通过函数生成:
store.dispatch(                 // <--- 推荐
 addTodo('Learn Redux')
);

[4] ----------------------------------------------------------------------------------------------------------------------------------------> Reducer

Store 收到 Action 以后,必须给出一个新的 State,View 才能发生变化。

Reducer:新State 的计算过程,based on old state。

const defaultState = 0;
const reducer = (state = defaultState, action) => { /**
* reducer 函数里面不能改变 State,必须返回一个全新的对象
*/
switch (action.type) {
case 'ADD':
return state + action.payload;
default:
return state;
}
};
.................................................... const state = reducer(1, {
type: 'ADD',
payload: 2
});

因为createStore(reducer),每当store.dispatch发送过来一个新的 Action,就会自动调用 Reducer,得到新的 State。

reducer 作为参数,为 "action们" 提供趁手的工具。

const actions = [
{ type: 'ADD', payload: 0 },
{ type: 'ADD', payload: 1 },
{ type: 'ADD', payload: 2 }
];

/**
* action是数据,打算使用reducer这个工具来处理,最后返回一个新的状态
*/
const total = actions.reduce(reducer, 0);   // 3

 

另外:最好把 State 对象设成只读,这样你没法改变它,要得到新的 State,唯一办法就是生成一个新对象。

// State 是一个对象
function reducer(state, action) {
return Object.assign({}, state, { thingToChange });
// 或者
return { ...state, ...newState };
} // State 是一个数组
function reducer(state, action) {
return [...state, newItem];
}

[5] ---------------------------------------------------------------------------------------------------------------------------------------- listener

store改变,提醒 listener,触发view改变。

解除 listener 竟然是利用其"返回值"。

let unsubscribe = store.subscribe(() =>
console.log(store.getState())
); unsubscribe();

二、Store 的实现

Store 提供了三个方法:

    • store.getState()   [1]
    • store.dispatch()   [3]
    • store.subscribe()   [5]

store 的三个部分,如下:

import { createStore } from 'redux';
let { subscribe, dispatch, getState } = createStore(reducer);
let store                  = createStore(todoApp, window.STATE_FROM_SERVER)  
// 第二个参数表示:整个应用的状态初始值,会覆盖 Reducer 函数的默认初始值

【createStore内部实现暂不深究】

三、Reducer 的拆分

  • 原始版本:Switch 写法,各种情况都在一个函数中

三种 Action 分别改变 State 的三个属性。

const chatReducer = (state = defaultState, action = {}) => {
const { type, payload } = action;
switch (type) {
............................................................. ADD_CHAT:chatLog属性
case ADD_CHAT:
return Object.assign({}, state, {
chatLog: state.chatLog.concat(payload)
});
............................................................. CHANGE_STATUS:statusMessage属性
case CHANGE_STATUS:
return Object.assign({}, state, {
statusMessage: payload
});
............................................................. CHANGE_USERNAME:userName属性
case CHANGE_USERNAME:
return Object.assign({}, state, {
userName: payload
});
default: return state;
}
};
  • 拆分版本:Reducer 函数中的 "switch部分" 被拆成了三个小函数,每一个负责生成对应的属性
const chatReducer = (state = defaultState, action = {}) => {
return {
chatLog: chatLog(state.chatLog, action),              // 函数名字重复也碍眼,参数也不太想多写
statusMessage: statusMessage(state.statusMessage, action),
userName: userName(state.userName, action)
}
};

理由: 这种拆分与 React 应用的结构相吻合:一个 React 根组件由很多子组件构成。这就是说,子组件与子 Reducer 完全可以对应。

  • 专业拆分使用combineReducers方法,专门用于拆分

这种写法有一个前提,就是 State 的属性名必须与子 Reducer 同名。

import { combineReducers } from 'redux';

/**
* 先找个地儿,定义各个子 Reducer 函数,
* 然后用这个方法,将它们合成一个大的 Reducer
*/
const chatReducer = combineReducers({
chatLog,
statusMessage,
userName
}) export default todoApp;
  • Reducer文件:把所有子 Reducer 放在一个文件里面,然后统一引入
import { combineReducers } from 'redux'
import * as reducers from './reducers' const reducer = combineReducers(reducers)

实例分析


一、流程梳理

怎么改变状态?

如何触发界面更新?

这些都是Store的活儿!

* 首先,用户发出 Action --> store。

store.dispatch(action);

* 然后,Store 自动调用 Reducer,并且传入两个参数:[当前 State][收到的 Action],返回新的 State 。

let nextState = todoApp(previousState, action);   // 产生新状态

* State 一旦有变化,Store 就会调用监听函数。

/* 设置监听函数 */
store.subscribe(listener);
/* 如果使用的是 React,出发方式如下 */
function listerner() {
let newState = store.getState();   // 获得新状态
component.setState(newState); // 根据新状态更新界面
}

二、代码分析

Clicked: 3 times + - Increment if odd Increment async

  • index.js之主页面
const render = () => ReactDOM.render(
/* 自定义Counter控件的使用 */
<Counter
value ={store.getState()}   # 获得new state
onIncrement={() => store.dispatch({ type: 'INCREMENT' })}
onDecrement={() => store.dispatch({ type: 'DECREMENT' })}
/>,
rootEl
)
  render()
  store.subscribe(render)
  • reducer之代码

在复杂的情况下,state会是如何?这里的例子有点过于简单,没有表现。

export default (state = 0, action) => {                         # 产生新状态
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
  • Counter控件的实现
一个重要的特征是:
click后的执行实体都是外围的 {() => store.dispatch({ type: 'INCREMENT' })}
也就是,只发送一个信号 action.
class Counter extends Component {
constructor(props) {
super(props);
this.incrementAsync = this.incrementAsync.bind(this);
this.incrementIfOdd = this.incrementIfOdd.bind(this);
}

////////////////////////////////////////////////////////
incrementIfOdd() {
if (this.props.value % 2 !== 0) {
this.props.onIncrement()
}
} incrementAsync() {
setTimeout(this.props.onIncrement, 1000)
}

////////////////////////////////////////////////////////
render() {
const { value, onIncrement, onDecrement } = this.props
return (
<p>
Clicked: {value} times
{' '}
<button onClick={onIncrement}>
+
</button>
{' '}
<button onClick={onDecrement}>
-
</button>
{' '}
<button onClick={this.incrementIfOdd}>
Increment if odd
</button>
{' '}
<button onClick={this.incrementAsync}>
Increment async
</button>
</p>
)
}
}

[React] 11 - Redux: redux的更多相关文章

  1. React躬行记(11)——Redux基础

    Redux是一个可预测的状态容器,不但融合了函数式编程思想,还严格遵循了单向数据流的理念.Redux继承了Flux的架构思想,并在此基础上进行了精简.优化和扩展,力求用最少的API完成最主要的功能,它 ...

  2. Flux --> Redux --> Redux React 入门

    本文的目的很简单,介绍Redux相关概念用法 及其在React项目中的基本使用 假设你会一些ES6.会一些React.有看过Redux相关的文章,这篇入门小文应该能帮助你理一下相关的知识 一般来说,推 ...

  3. React,关于redux的一点小见解

    最近项目做多页面应用使用到了,react + webpack + redux + antd去构建多页面的应用,本地开发用express去模拟服务端程序(个人觉得可以换成dva).所以在这里吐槽一下我自 ...

  4. 在React中使用Redux

    这是Webpack+React系列配置过程记录的第六篇.其他内容请参考: 第一篇:使用webpack.babel.react.antdesign配置单页面应用开发环境 第二篇:使用react-rout ...

  5. Flux --> Redux --> Redux React 基础实例教程

    本文的目的很简单,介绍Redux相关概念用法 及其在React项目中的基本使用 假设你会一些ES6.会一些React.有看过Redux相关的文章,这篇入门小文应该能帮助你理一下相关的知识 一般来说,推 ...

  6. react系列(五)在React中使用Redux

    上一篇展示了Redux的基本使用,可以看到Redux非常简单易用,不限于React,也可以在Angular.Vue等框架中使用,只要需要Redux的设计思想的地方,就可以使用它. 这篇主要讲解在Rea ...

  7. Flux --> Redux --> Redux React 入门 基础实例使用

    本文的目的很简单,介绍Redux相关概念用法 及其在React项目中的基本使用 假设你会一些ES6.会一些React.有看过Redux相关的文章,这篇入门小文应该能帮助你理一下相关的知识 一般来说,推 ...

  8. [RN] React Native 使用 Redux 比较详细和深刻的教程

    React Native 使用 Redux 比较详细和深刻的教程 React Native 使用 Redux https://www.jianshu.com/p/06fc18cef56a http:/ ...

  9. React Hooks +React Context vs Redux

    React Hooks +React Context vs Redux https://blog.logrocket.com/use-hooks-and-context-not-react-and-r ...

随机推荐

  1. keybd_event 被 SendInput 替代

    keybd_event   函数功能:该函数合成一次击键事件.系统可使用这种合成的击键事件来产生WM_KEYUP或WM_KEYDOWN消息,键盘驱动程序的中断处理程序调用keybd_event函数.在 ...

  2. .Net Core Md5加密整理

    一..Net Core中Md5使用说明 .Net Core中自带Md5加密处理,使用方法和 .Net Framework中相同 所在命名空间 using System.Security.Cryptog ...

  3. solr中重建索引(转)

    Stop your application server Change your schema.xml file Start your application server Delete the in ...

  4. Android性能优化-App启动优化

    原文地址:https://developer.android.com/topic/performance/launch-time.html#common 通常用户期望app响应和加载速度越快越好.一个 ...

  5. VMware DHCP Service服务无法启动问题的解决

    我的电脑出现VMware DHCP Service和VMware NAT Service两个服务无法启动的问题: 打开VMware主界面,菜单->编辑->虚拟网络编辑器: 勾选上“将主机虚 ...

  6. puppet应用案例

  7. 【Java】MyBatis与Spring框架整合(二)

    本文讲解 Spring 注入映射器及事务功能的实现. 注入映射器实现 MyBatis 可以使用 SqlSession 的 getMapper ( Class<T> type ) 方法,根据 ...

  8. WCF系列(六) - WCF安全系列(一) - basicHttpBinding

    绑定可指定在与终结点通话时所使用的通信机制,并指示如何连接到终结点.绑定由一些元素组成,这些元素指定如何对 Windows Communication Foundation (WCF) 通道进行分层以 ...

  9. Java注解应用,自定义注解映射实现方案说明.

    插件结构如图: 注册模块定义了三个:用于实体与表映射的注解,用于属性到表字段的映射,用于映射时过滤掉的注解. 1.用于实体与表映射的注解 package com.dobby.plugins.annot ...

  10. React Native 设置RGBA背景色

    React Native 设置RGBA背景色: 可以先用Mac自带吸色工具,获取RGB值,然后设置背景如下: backgroundColor: 'rgba(52, 52, 52, 0.8)', 透明度 ...