该文为阅读笔记,建议大家去看阮一峰老师的原文,若有侵权请联系删除
为什么引入Redux?
- Web 应用的完整解决方案涉及完整代码、组件间通信,这对于大型应用至关重要。而React只是DOM的抽象层,难以满足大型应用的开发。
- 为了解决以上问题,随后,Facebook相继在2014年和2015年分别提出Flux和Redux。
一些不需要使用Redux的情况
- 用户的使用方式非常简单
- 用户之间没有协作
- 不需要与服务器大量交互,也没有使用 WebSocket
- 视图层(View)只从单一来源获取数据
适合Redux使用的场景
Store
- 作用:保存数据的容器
State
- 作用:保存在Store中的状态
- 注:一个State对应一个View
Action
State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。
- 作用:View发出的改变State的通知
const action = {
type: 'ADD_TODO',
payload: 'Learn Redux'
};
其中,type为必填,表示当前发生事情的名称。其他为选填
store.dispatch
- 作用:View发处Action的唯一方法
import { createStore } from 'redux';
const store = createStore(fn);
store.dispatch({
type: 'ADD_TODO',
payload: 'Learn Redux'
});
store.dispatch接受一个 Action 对象作为参数
Reducer
- 概念:Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。
const defaultState = 0;
const reducer = (state = defaultState, action) => {
switch (action.type) {
case 'ADD':
return state + action.payload;
default:
return state;
}
};
const state = reducer(1, {
type: 'ADD',
payload: 2
});
reducer函数收到名为ADD的 Action 以后,就返回一个新的 State,作为加法的计算结果。
Reducer是纯函数
约束条件
- 不得改写参数
- 不能调用系统 I/O 的API
- 不能调用
Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果
由于 Reducer 是纯函数,就可以保证同样的State,必定得到同样的 View。但也正因为这一点,Reducer 函数里面不能改变 State,必须返回一个全新的对象。
要得到新的 State,唯一办法就是生成一个新对象
// State 是一个对象
function reducer(state, action) {
return Object.assign({}, state, { thingToChange });
// 或者
return { ...state, ...newState };
}
// State 是一个数组
function reducer(state, action) {
return [...state, newItem];
}
store.subscribe()
Store 允许使用store.subscribe方法设置监听函数,一旦 State 发生变化,就自动执行这个函数。
Reducer的拆分
- 起初,由于整个应用只有一个 State 对象,包含所有数据,对于大型应用来说,这个 State 必然十分庞大,导致 Reducer 函数也十分庞大。
const chatReducer = (state = defaultState, action = {}) => {
const { type, payload } = action;
switch (type) {
case ADD_CHAT:
return Object.assign({}, state, {
chatLog: state.chatLog.concat(payload)
});
case CHANGE_STATUS:
return Object.assign({}, state, {
statusMessage: payload
});
case CHANGE_USERNAME:
return Object.assign({}, state, {
userName: payload
});
default: return state;
}
};
- 接着把 Reducer 函数拆分。不同的函数负责处理不同属性,最终把它们合并成一个大的 Reducer 即可。
const chatReducer = (state = defaultState, action = {}) => {
return {
chatLog: chatLog(state.chatLog, action),
statusMessage: statusMessage(state.statusMessage, action),
userName: userName(state.userName, action)
}
};
- 最后Redux 提供了一个
combineReducers方法,用于 Reducer 的拆分。
import { combineReducers } from 'redux';
const chatReducer = combineReducers({
chatLog,
statusMessage,
userName
})
export default todoApp;
两种写法:
const reducer = combineReducers({
a: doSomethingWithA,
b: processB,
c: c
})
// 等同于
function reducer(state = {}, action) {
return {
a: doSomethingWithA(state.a, action),
b: processB(state.b, action),
c: c(state.c, action)
}
}
工作流程
- 步骤 首先,用户发出 Action。
store.dispatch(action);
然后,Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action。 Reducer 会返回新的 State 。
let nextState = todoApp(previousState, action);
State 一旦有变化,Store 就会调用监听函数。
// 设置监听函数
store.subscribe(listener);
listener可以通过store.getState()得到当前状态。如果使用的是 React,这时可以触发重新渲染 View。
function listerner() {
let newState = store.getState();
component.setState(newState);
}