logo头像
Snippet 博客主题

React入门——TodoList(三)

引入Redux

Redux = Reducer + Flux

工作流程

Redux工作流程

Store

Store 就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。

Redux 提供 createStore 这个函数,用来生成 Store。

1
2
import { createStore } from 'redux';
const store = createStore(reducer);

State

Store对象包含所有数据。如果想得到某个时点的数据,就要对 Store 生成快照。这种时点的数据集合,就叫做 State。

当前时刻的 State,可以通过 store.getState() 拿到。

1
2
3
4
import { createStore } from 'redux';
const store = createStore(reducer);

const state = store.getState();

Action

Action 是一个对象。其中的type属性是必须的,表示 Action 的名称。其他属性可以自由设置。

1
{type: ”ADD”, key1: ”“,key2: ”“}

Action Creator

View 要发送多少种消息,就会有多少种 Action。如果都手写,会很麻烦。可以定义一个函数来生成 Action,这个函数就叫 Action Creator。

1
2
3
4
5
6
7
8
9
10
const ADD_TODO = '添加 TODO';

function addTodo(text) {
return {
type: ADD_TODO,
text
}
}

const action = addTodo('Learn Redux');

Reducer

Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫做 Reducer。

Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。

1
2
3
4
const reducer = function (state, action) {
// ...
return new_state;
};

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

为什么这个函数叫做 Reducer 呢?因为它可以作为数组的 reduce 方法的参数。请看下面的例子,一系列 Action 对象按照顺序作为一个数组。

1
2
3
4
5
6
7
const actions = [
{ type: 'ADD', payload: 0 },
{ type: 'ADD', payload: 1 },
{ type: 'ADD', payload: 2 }
];

const total = actions.reduce(reducer, 0); // 3

三个基本原则

  1. store必须是唯一的
  2. 只有store能够改变自己的内容
  3. Reducer必须是纯函数

纯函数指的是,给固定的输入,就一定会有固定的输出。而且不会有任何副作用

数据流

1.调用 store.dispatch(action)

2.Redux store 调用传入的 reducer 函数。

3.根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树

4.Redux store 保存了根 reducer 返回的完整 state 树。

Redux核心API

  • createStore
  • store.dispatch
  • store.getState
  • store.subscribe

redux-thunk中间件

让 store.dispatch 方法可接收函数
步骤:

  1. yarn add redux-thunk 安装
  2. 与 REDUX_DEVTOOLS 一起使用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import { createStore, applyMiddleware, compose } from 'redux';
    import reducer from './reducer';
    import thunk from 'redux-thunk';

    const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;

    const enhancer = composeEnhancers(
    applyMiddleware(thunk),
    );
    const store = createStore(reducer, enhancer);

    export default store

3.把异步操作移到 actionCreator

1
2
3
4
5
6
7
8
9
export const getTodoList = () => {
return (dispatch) => {
axios.get('/list.json').then((res) => {
const data = res.data;
const action = initListAction(data);
dispatch(action);
})
}
}

4.在组件中提交 action

1
2
3
4
componentDidMount() {
const action = getTodoList();
store.dispatch(action);
}

中间件

action 跟 reducer 的中间,对 dispatch 方法的包装升级
applyMiddleware源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
var store = createStore(reducer, preloadedState, enhancer);
var dispatch = store.dispatch;
var chain = [];

var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
};
chain = middlewares.map(middleware => middleware(middlewareAPI));
dispatch = compose(...chain)(store.dispatch);

return {...store, dispatch}
}
}

React-redux的使用

Provider组件
connect 连接组件和store
mapStateToProps 组件和store的映射
mapDispatchToProps store.dispatch挂载到props