一. connect()
react-redux 提供了 connect
方法,用于将一个UI组件包装成一个容器组件。使用方法如下:
import React, {Component} from 'react';
import {connect} from 'react-redux';
class List extends Component {
}
export default connect(mapStateToProps, mapDispatchToProps)(List);
其中 connect 方法接受两个参数 mapStateToProps
和 mapDispatchToProps
,前者负责输入逻辑,将 外部(store)中的状态state映射为当前组件的属性props,后者负责输出逻辑,将用户的各种操作映射为Action输出出去。
二. mapStateToProps(state)
connect中的这个参数负责将外部的状态映射为当前组件的属性。方法返回一个对象,这个对象即向组件中添加的映射属性。
const mapStateToProps = (state) => ({
listLength: state.listLength
});
上例中向该组件中添加了一个listLength属性,该属性的值从外部的state中获取。
mapStateToProps方法作为connect 方法的第一个参数可以被省略,省略后表示组件属性不会订阅外部的状态。
三. mapDispatchToProps()
connect的这个参数是一个返回对象的函数,返回的对象中定义了props 和 dispatch(Action)的对应关系。
const mapDispatchToProps = (dispatch) => {
return {
onClick: () => {
dispatch({type: 'ON_CLICK', payload: {}});
}
}
};
上例中在该组件中添加了一个onClick属性,该属性被调用时会发送一个名为‘ON_CLICK’的 Action。
mapDispatchToProps 也可以直接是一个对象,上例中代码也可以写成这样:
const mapDispatchToProps = {
onClick: () => ({type: 'ON_CLICK', payload: {}})
};
写成对象时,对象的key就是该组件新增的属性,对应的value是一个返回Action对象的函数,即Action Creator。
四. Provider
react-redux 提供了 <Provider />
组件方便为所有的子组件拿到state。store是state的存储器,作为参数被传入到Provider组件。
import {Provider} from 'react-redux';
render(){
return (
<Provider store={store}>
<App/>
</Provider>
)
}
Provider 组件一般应在整个应用的最外层,嵌套之后,其下的全部组件均可获取store中的state数据。
五. createStroe
redux 提供 createStroe
方法,该方法有三个参数,第一个参数定于reducer,第二个参数定义store的初始状态,最后一个参数引入中间件。
import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
const store = createStore(reducer, initalState, applyMiddleware(thunk));
初始状态就是一个形如下例的对象:
const initalState = {
listLength: 0
};
六. reducer
Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。
const reducer = (state = {}, action) => {
switch (action.type) {
case 'ON_CLICK': {
return {...state, ...action.payload}
}
default: {
return {...state};
}
}
};
上例中的reducer判断当Action为‘ON_CLICK’时,会将action中的 payload 合并到state中去。
七. combineReducers
当我们的应用比较庞大的时候,所有的reducer聚集到一起会非常多,这时候我们可以通过 combineReducers
对reducer按模块进行划分。
import {combineReducers} from 'redux';
const initalState = {
layout: {
siderOpen: true
},
data: {
menuList: [],
appLoading: false
}
};
const reducer = combineReducers({
layout: (state = {}, action) => { // 这里的state 实际上是 state.layout
switch (action.type) {
case 'ON_CLICK': {
return {...state, ...action.payload}
}
default: {
return {...state};
}
}
},
data: (state = {}, action) => { // 这里的state 实际上是 state.data
switch (action.type) {
case 'DATA_CLICK': {
return {...state, ...action.payload}
}
default: {
return {...state};
}
}
}
});
如上例,combineReducers 由 redux 提供,参数为多个 Reducer 组成的一个对象,对象的 key 为分类名称,value 为对应的 reducer。需要注意的是,在使用了 combineReducers 后,store 中 state 的结构需要与 combineReducers 中的分类相对应,即在 layout 分类下的 reducer 操作的 state 实际上是 store 中的 state.layout。
八. 异步操作 和 applyMiddleware
action 发起后 Reducer 立即算出 State 这中间没有供我们进行异步操作的余地,因为我们没有办法在 Reducer 在异步操作结束后自动执行其他操作。此时我们需要引入 中间件,如 redux-trunk。redux-trunk在被引入后,dispatch()的参数 由原来的 只能是一个形如{type:‘XX’,payload:{}}这样的对象,变成了也可以为一个函数。
const mapDispatchToProps = (dispatch) => {
return {
fetchMenu: () => {
dispatch(function (dispatch) {
dispatch({XXXX:XXX});
axios.get("/api/v1/menu", {dataType: 'json'}).then(res => {
dispatch({XXXX:XXX});
});
})
}
}
};
上例中原来的 dispatch(Action) 变为了 dispatch(function),在function里面先发出了一个action,然后进行异步操作后再次发出一个Action,从而实现了效果。
上例改写为 Action Creater的形式如下:
const mapDispatchToProps = {
fetchMenu: () => {
return (dispatch) => {
dispatch({type: 'FETCH_START'});
axios.get("/api/v1/menu", {dataType: 'json'}).then(res => {
dispatch({type: 'FETCH_SUCCESS', payload: res.data});
});
}
}
}
Action creator 不在返回一个 Action对象 ,而是一个方法。