redux介绍
redux是一个针对JavaScript应用的可预测的状态管理器。
redux中的设计模式
装饰者模式
定义:装饰者模式用于给对象动态地增加职责。
我们来看看redux最早期(v0.2.0)的github代码:
- //Counter.js
- import React from 'react';
- import { performs,observes } from 'redux';
- @performs('increment','decrement','double')
- @observes('CounterStore')
- export default class Counter {
- render() {
- const { increment,decrement } = this.props;
- return (
- <p>
- Clicked: {this.props.counter} times
- {' '}
- <button onClick={() => increment()}>+</button>
- {' '}
- <button onClick={() => decrement()}>-</button>
- {' '}
- <button onClick={() => double()}>double</button>
- </p>
- );
- }
- }
经过observes的包装后,react组件可以访问Redux store里的couter数据;经过performs的包装后,react组件可以发起increment、decrement和double这3个Action。
我们来看看performs是怎么包装react组件的:
- //performs.js
- import React,{ Component,PropTypes } from 'react';
- import pick from 'lodash/object/pick';
- import identity from 'lodash/utility/identity';
- const contextTypes = {
- getActions: PropTypes.func.isrequired
- };
- export default function performs(...actionKeys) {
- let mapActions = identity;
- return function (DecoratedComponent) {
- const wrappedDisplayName = DecoratedComponent.name;
- return class extends Component {
- static displayName = `ReduxPerforms(${wrappedDisplayName})`;
- static contextTypes = contextTypes;
- constructor(props,context) {
- super(props,context);
- this.updateActions(props);
- }
- updateActions(props) {
- this.actions = mapActions(
- pick(this.context.getActions(),actionKeys),props
- );
- }
- render() {
- return (
- <DecoratedComponent {...this.actions} />
- );
- }
- };
- };
- }
很简单对不对,performs实质上是一个高阶函数,接收一个react组件类型的参数DecoratedComponent,然后返回一个高阶组件,该组件包装了传递进来的react组件,并向该组件传递了action相关的props.
通过可以看上面的图可以看出,Counter组件被Observes包装后,又被performs包装,形成了一条包装链。
redux提供的API中,有一个重要的方法connect,用于连接 React 组件与 Redux store。连接操作不会改变原来的组件类,而是返回一个新的已与 Redux store 连接的组件类。典型的装饰者模式有木有?
观察者模式
定义:观察者模式又叫发布-订阅模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都将得到通知。
- @observes('CounterStore')
counter.js的这行代码表示它对Redux的CounterStore数据进行订阅。我们来看看objserves的实现:
- //observes.js
- import React,PropTypes } from 'react';
- import pick from 'lodash/object/pick';
- const contextTypes = {
- observeStores: PropTypes.func.isrequired
- };
- export default function connect(...storeKeys) {
- return function (DecoratedComponent) {
- const wrappedDisplayName = DecoratedComponent.name;
- return class extends Component {
- static displayName = `ReduxObserves(${wrappedDisplayName})`;
- static contextTypes = contextTypes;
- constructor(props,context);
- this.handleChange = this.handleChange.bind(this);
- this.unobserve = this.context.observeStores(storeKeys,this.handleChange); //订阅store数据
- }
- handleChange(stateFromStores) {
- this.currentStateFromStores = pick(stateFromStores,storeKeys);
- this.updateState(stateFromStores);
- }
- updateState(stateFromStores,props) {
- stateFromStores = stateFromStores[storeKeys[0]];
- const state = stateFromStores;
- this.setState(state);//通过setState进行组件更新
- }
- componentWillUnmount() {
- this.unobserve();//退订
- }
- render() {
- return (
- <DecoratedComponent {...this.props}
- {...this.state} />
- );
- }
- };
- };
- }