又是一个无味的星期一。看了一上午的redux相关知识,每次去看,几乎每次都有新的收获。这让我既是开心又是无奈…
redux核心
整体感知
用我自己浅陋的理解来叙一叙吧。
redux是一个专门用来管理应用状态的库。它的核心是store,围绕着store有state(一个大对象,包含所有状态数据),action(描述一个动作),reducer(根据不同类型的action来得到新的state)。
它的工作流程是:①store.dispatch(‘ACTION1’)–>②自动触发reducer函数,返回新的state–>③render函数订阅state的变化。
store
创建store时传入的参数有reducer函数,初始状态值,中间件。
store主要提供了一些函数:1
2
3
4
5
6// 获取应用的状态数据
store.getState()
// 派发一个动作,从而触发reducer
store.dispatch()
// 参数里面放state改变后的操作,如重新渲染视图
store.subscribe()
action
action是一个普通的javascript对象,它必须包含type属性来区分不同的action。
我们一般不会用字面量的方式去创建action,而是通过一个action生成函数来创建action。这个actionCreator函数可以做一些比较猥琐的事儿。这是后话,暂且不提。
reducer
reducer是一个纯函数。里面是判断action的类型,根据原始state和传入的action生成新的state的具体操作。
reducer的拆分
当state特别大时,我们需要对reducer进行拆分(拆分的是state的直系属性)。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import { combineReducers } from 'redux';
const totalReducer = combineReducers({
stateA : reducerA,
stateB : reducerB,
stateC : reducerC
})
// 等同于
/*function totalReducer(state = {}, action) {
return {
stateA: reducerA(state.a, action),
stateB: reducerB(state.b, action),
stateC: reducerC(state.c, action)
}
}*/
export default totalReducer;
redux中间件
为什么需要redux的中间件
redux中间件是用来增强store.dispatch()的。原始的dispatch方法只能接收一个action对象作为参数。但是使用了中间件之后,dispatch方法可以接收函数、promise对象等作为参数。
中间件的用法
1 | import { applyMiddleware, createStore } from 'redux'; |
redux-thunk中间件
Action Creator的写法如下:1
2
3
4
5
6
7
8
9
10
11
12
13// fetchPosts函数返回了一个函数
const fetchPosts = postTitle =>
// 这个就是返回的函数
(dispatch) => {
// dispatch一个同步的action,表示操作开始
dispatch(requestPosts(postTitle));
// 使用fetch发送异步请求(目测fetch里面可以直接使用then,而且每一次用到fetch时,都是return打头阵),
return fetch(`/some/API/${postTitle}.json`)
.then(response => response.json())
// 派发结束action
.then(json => dispatch(receivePosts(postTitle, json)));
};
};
redux-thunk中间件的用法:①在创建store的时候传入applyMiddleware(thunk)
–>②派发动作store.dispatch(fetchPosts('reactjs'))
(dispatch之后还可以继续.then()
)
redux-promise中间件
redux-promise中间件使dispatch支持promise对象作为参数。
Action Creator的写法一:1
2
3
4
5
6
7
8const fetchPosts = (dispatch, postTitle) => new Promise(function (resolve, reject) {
dispatch(requestPosts(postTitle));
return fetch(`/some/API/${postTitle}.json`)
.then(response => {
type: 'FETCH_POSTS',
payload: response.json()
});
});
Action Creator的写法二:1
2
3
4
5
6dispatch(createAction(
'FETCH_POSTS',
// 这个action的payload为promise对象
fetch(`/some/API/${postTitle}.json`)
.then(response => response.json())
));
react-redux
UI组件(木偶组件)
负责渲染页面,数据全部由props提供,没有自己的state。
容器组件
由react-redux生成,有自己的状态,管理数据和业务逻辑。
connect方法
用于根据UI组件生成容器组件。1
2
3
4
5import { connect } from 'react-redux'
const VisibleTodoList = connect(
mapStateToProps, // 建立state到props的映射
mapDispatchToProps // 建立dispatch到props的映射
)(TodoList) // TodoList为UI组件
mapStateToProps()
1 | const mapStateToProps = (state) => { |
补充:mapStateToProps的第一个参数总是state对象,还可以使用第二个参数,代表容器组件的props对象。
mapDispatchToProps()
写法一(函数形式)1
2
3
4
5
6
7
8
9
10
11
12
13const mapDispatchToProps = (
dispatch,
ownProps // 容器组件的props对象
) => {
return {
onClick: () => { // onClick为UI组件里的同名参数
dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: ownProps.filter
});
}
};
}
写法二(对象形式)1
2
3
4
5
6
7// 返回的 Action 会由 Redux 自动发出
const mapDispatchToProps = {
onClick: (filter) => {
type: 'SET_VISIBILITY_FILTER',
filter: filter
};
}
组件
在根组件外面包一层
一个真实项目中的应用
入口文件
1 | // index.jsx |
定义action的名字
1 | // app/contants/userinfo.js |
定义action生成函数
1 | // app/actions/userinfo.js |
定义reducers
1 | // app/reducers/userinfo.js |
生成store
1 | // app/store/configureStore.js |
配合react-redux
1 | // app/appContainer.jsx,导入action生成函数 |
redux亲手填坑
redux相关目录
|redux
—-|constants
——–|module1.js(action名常量)
——–|…
—-|actions
——–|module1.js(生成action对象的工厂函数)
——–|…
—-|reducers
——–|module1.js
——–|…
——–|index.js(合并各个reducer)
—-|index.js(创建store,传入reducer)
constants
1 | // 定义action的名字(module1.js) |
actions
1 | import * as module1Types from '../constants/module1.js' |
reducers
1 | /* module1.js */ |
1 | /* index.js */ |
最外层定义store的index.js
1 | import { createStore } from 'redux' |
在react上注册store
1 | import { Provider } from 'react-redux'; |
在组件中与store交互
1 | import { connect } from 'react-redux' |