react-redux
react-redux是什么
1) 一个react插件库
2) 专门用来简化react应用中使用redux
上一篇中我们已经利用redux实现了基本的通信需求. 然而为了简化其写法.
如读取数据 采用
let state = this.props.store.getState();每一次读取都需要调用getState修改数据 采用
this.props.store.dispatch({type:INCREASE,data: num })每一次修改都需要dispatch.我们可以通过react-redux插件来用更简单的写法来更加优雅地实现上述功能.(以及解决多层传递问题)
思考一下react-redux到底干了什么?
首先让我们回忆一下redux在干什么?
redux本质是实现 集中式管理react应用中多个组件共享的状态 , 是组件间通信的第三种方式. 通过redux中的store来存储状态与方法, 而不是将状态与方法存放在组件中.
redux的思路: component只提供接口(props各属性), 通过各属性接受状态与方法.
redux实现步骤:
redux部分:
定义状态, 状态变化规则 (各类reducer函数 ), 根据state和action(type, data)返回新的state.
目前暂且state的定义还是在传参的默认值设定.
1
2
3
4
5
6
7
8
9
10
11
12export function counter(state =0, action){
switch (action.type){
case INCREASE:
return state + action.data
case DECREASE:
return state - action.data
case INCREASASYCN:
return state + action.data
default:
return state;
}
}根据reducer生成store,
const store = createStore(counter);store传入所需component,
<App store={store} />store与render挂钩, 手动重绘
store.subscribe(render)
component部分
- 在props的store中获取状态,
this.props.store.getState(); - 在修改数据的方法其实并没有真实地发送给component, 而提供store的dispatch方法, 传入一个action, 进而在store中自己利用reducer来进行状态的改变. ( 而这也是为什么要手动重绘的核心 )
- 在props的store中获取状态,
其他辅助部分
1. action-types 定义action type, 将字符串封装成变量 2. action-creator 提供action生成函数
对比一下react-redux是如何解决上述问题的
React-Redux 将所有组件分成两大类:UI 组件(presentational component)和容器组件(container component)。
UI 组件有以下几个特征。
- 只负责 UI 的呈现,不带有任何业务逻辑
- 没有状态(即不使用
this.state这个变量)- 所有数据都由参数(
this.props)提供- 不使用任何 Redux 的 API
容器组件的特征恰恰相反。
- 负责管理数据和业务逻辑,不负责 UI 的呈现
- 带有内部状态
- 使用 Redux 的 API
其实和redux的解决思路的区别在于: redux是将整个store全部交给 presentational component, 因此其中会使用redux的API. 而react-redux则将store的解析交由connect函数处理.
redux部分:
定义状态, 状态变化规则 (各类reducer函数 ), 根据state和action(type, data)返回新的state.
目前暂且state的定义还是在传参的默认值设定.
1
2
3
4
5
6
7
8
9
10
11
12export function counter(state =0, action){
switch (action.type){
case INCREASE:
return state + action.data
case DECREASE:
return state - action.data
case INCREASASYCN:
return state + action.data
default:
return state;
}
}根据reducer生成store,
const store = createStore(counter);
不再是 store传入所需component,
<App store={store} />变为 而是将store传给Provider组件
1
2
3
4import {Provider} from 'react-redux';
<Provider store={store}>
<App />
</Provider>不再是 store与render挂钩, 手动重绘
store.subscribe(render)变为 无需手动订阅, 在connect中自动订阅.
component部分
UIcomponent需要的store中的数据和方法都默认从props中获取.
this.props.countthis.props.increase(num)使用connect将store中的数据抽离交给UIcomponent.
1
2
3
4export default connect(
state =>({count: state}), //mapStateToProps,
{increase: increaseCreator, decrease:dereaseCreator}//mapDispatchToProps
)(Counter)// UI componentmapStateToProps
mapStateToProps是一个函数。建立一个从(外部的)state对象到(UI 组件的)props对象的映射关系。应该返回一个对象,里面的每一个键值对就是一个映射。mapStateToProps会订阅 Store,每当state更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。mapStateToProps的第一个参数总是state对象,还可以使用第二个参数,代表容器组件的props对象, 用于获取组件的内部数据。connect方法可以省略mapStateToProps参数,那样的话,UI 组件就不会订阅Store,就是说 Store 的更新不会引起 UI 组件的更新。mapDispatchToProps
mapDispatchToProps是connect函数的第二个参数,用来建立 UI 组件的参数到store.dispatch方法的映射。如果
mapDispatchToProps是一个对象,它的每个键名也是对应 UI 组件的同名参数,键值应该是一个函数,会被当作 Action creator ,返回的 Action 会由 Redux 自动发出。对应本例子, 在UI component中调用对应 Action creator的同名参数, 其实this.props.increase(num)等价于纯redux版本中的this.props.store.dispatch(actionCreator.increaseCreator(num))即: 生成action后自动发出.
其他辅助部分
1. action-types 定义action type, 将字符串封装成变量 2. action-creator 提供action生成函数
react-redux优势
presentational component 中不再包含redux API, 很纯粹
多级传递被解决! 将
state对象作为参数,传入容器组件。但是,这样做比较麻烦,尤其是容器组件可能在很深的层级,一级级将state传下去就很麻烦。Provider在根组件外面包了一层,这样一来,App的所有子组件就默认都可以拿到state了。原理:
React组件的context属性,请看源码。1
2
3
4
5
6
7
8
9
10
11
12
13
14class Provider extends Component {
getChildContext() {
return {
store: this.props.store
};
}
render() {
return this.props.children;
}
}
Provider.childContextTypes = {
store: React.PropTypes.object
}上面代码中,
store放在了上下文对象context上面。然后,子组件就可以从context拿到store,代码大致如下。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class VisibleTodoList extends Component {
componentDidMount() {
const { store } = this.context;
this.unsubscribe = store.subscribe(() =>
this.forceUpdate()
);
}
render() {
const props = this.props;
const { store } = this.context;
const state = store.getState();
// ...
}
}
VisibleTodoList.contextTypes = {
store: React.PropTypes.object
}React-Redux自动生成的容器组件的代码,就类似上面这样,从而拿到store。
补充
使用React-Router的项目,与其他项目没有不同之处,也是使用Provider在Router外面包一层,毕竟Provider的唯一功能就是传入store对象。
1
2
3
4
5
6
7 const Root = ({ store }) => (
<Provider store={store}>
<Router>
<Route path="/" component={App} />
</Router>
</Provider>
);


.png)