flux和redux

149 阅读2分钟

flux是什么?

flux是一种状态管理框架。严格版的MVC框架。基本原则:

  • 单向数据流
  • 保存状态只读

缺点:

  • 1、Store之间依赖关系。
  • 2、难以进行服务端渲染。因为每个Store都是全局唯一的对象
  • 3、Store混杂了逻辑和状态。Store封装了数据和处理逻辑,不合适热加载

在flux体系中,如果两个Store之间有逻辑依赖关系,就必须用上Dispatcher.waitFor(dispatchToken)函数。dispatchToken是AppDispatcher.rgister返回的来用于识别Store的,这样产生了不同Store之间的显示依赖关系。如果状态数据分散在多个Store中,容易造成数据冗余。

Dispatcher对象的作用是把一个action对象分发给多个注册了的Store

redux

redux(reducer+flux)强调三个基本原则:

  • 单向数据流,只存储在唯一的一个Store上
  • 保存状态只读。不能直接修改状态,要修改Store的状态,必须要通过派发action对象完成
  • 数据改变只能通过纯函数完成 这个纯函数就是reducer(state, action),根据state和action产生新的对象然后返回。返回值必须完全由state和action决定,而且不产生任何副作用,也不能修改参数state和action对象。reducer只负责计算,不负责存储状态

flux

//ActionType.js
export const INCREMENT = 'increment';
export const DECREMENT = 'decrement';
//CounterActions.js
import * as ActionTypes from './ActionTypes.js';
import AppDispatcher from './AppDispatcher.js';

export const increment = (counterCaption) => {
  AppDispatcher.dispatch({
      type: ActionTypes.INCREMENT,
    counterCaption: counterCaption
  });
};

export const decrement = (counterCaption) => {
  AppDispatcher.dispatch({
    type: ActionTypes.DECREMENT,
    counterCaption: counterCaption
  });
};
//AppDispatcher.js
import {Dispatcher} from 'flux';
export default new Dispatcher();
//CounterStore.js
import AppDispatcher from '../AppDispatcher.js';
import * as ActionTypes from '../ActionTypes.js';
import {EventEmitter} from 'events';

const CHANGE_EVENT = 'changed';
const counterValues = {
  'First': 0,
  'Second': 10,
  'Third': 30
};

const CounterStore = Object.assign({}, EventEmitter.prototype, {
  getCounterValues: function() {
    return counterValues;
  },

  emitChange: function() {
    this.emit(CHANGE_EVENT);
  },

  addChangeListener: function(callback) {
    this.on(CHANGE_EVENT, callback);
  },

  removeChangeListener: function(callback) {
    this.removeListener(CHANGE_EVENT, callback);
  }
});

CounterStore.dispatchToken = AppDispatcher.register((action) => {
    if (action.type === ActionTypes.INCREMENT) {
        counterValues[action.counterCaption]++;
        CounterStore.emitChange();
    } else if (action.type === ActionTypes.DECREMENT) {
        counterValues[action.counterCaption]--;
        CounterStore.emitChange();
    } 
});

export default CounterStore;
//Counter.js
import CounterStore from '../stores/CounterStore.js';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.onChange = this.onChange.bind(this);
    this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
    this.onClickDecrementButton = this.onClickDecrementButton.bind(this);
    this.state = {
      count: CounterStore.getCounterValues()[props.caption]
    }
  }
  shouldComponentUpdate(nextProps, nextState) {
    return (nextProps.caption !== this.props.caption) ||
           (nextState.count !== this.state.count);
  }
  componentDidMount() {
    CounterStore.addChangeListener(this.onChange);
  }
  componentWillUnmount() {
    CounterStore.removeChangeListener(this.onChange);
  }

  onChange() {
    const newCount = CounterStore.getCounterValues()[this.props.caption];
    this.setState({count: newCount});
  }

  onClickIncrementButton() {
    Actions.increment(this.props.caption);
  }

  onClickDecrementButton() {
    Actions.decrement(this.props.caption);
  }

  render() {
    const {caption} = this.props;
    return (
      <div>
        <button onClick={this.onClickIncrementButton}>+</button>
        <button onClick={this.onClickDecrementButton}>-</button>
        <span>{caption} count: {this.state.count}</span>
      </div>
    );
  }
}
Counter.propTypes = {
  caption: PropTypes.string.isRequired
};
export default Counter;

redux区别于flux:

  • 1、action构造函数只负责创建一个对象并返回,通过store.dispatch派发action。而flux的action会dispatcher实现分发给store
  • 2、只有一个store。而flux有多个store,更新数据,
  • 3、新增reducer纯函数,负责计算,返回一个新的state
//CounterAction.js 返回一个action对象
import * as ActionTypes from './ActionTypes.js';
export const increment = (counterCaption) => {
  return {
    type: ActionTypes.INCREMENT,
    counterCaption: counterCaption
  };
};
export const decrement = (counterCaption) => {
  return {
    type: ActionTypes.DECREMENT,
    counterCaption: counterCaption
  };
};
//Store.js 只有一个store
import {createStore} from 'redux';
import CounterReducer from './CounterReducer.js';

const initValues = {
  'First': 0,
  'Second': 10,
  'Third': 20
};
const store = createStore(CounterReducer, initValues);
export default store;
//CounterReducer.js 只负责计算,不负责存储状态
import * as ActionTypes from './ActionTypes.js';

export default (state, action) => {
  const {counterCaption} = action;

  switch (action.type) {
    case ActionTypes.INCREMENT:
      return {...state, [counterCaption]: state[counterCaption] + 1};
    case ActionTypes.DECREMENT:
      return {...state, [counterCaption]: state[counterCaption] - 1};
    default:
      return state
  }
}
//Cunter.js 
import store from '../Store.js';
import * as Actions from '../Actions.js';

class Counter extends Component {
constructor(props) {
    super(props);
    this.state = this.getOwnState();
  }
  getOwnState() {
    return {
      value: store.getState()[this.props.caption]
    };
  }
  componentDidMount() {
    store.subscribe(this.onChange);
  }
  componentWillUnmount() {
    store.unsubscribe(this.onChange);
  }
  onChange() {
    this.setState(this.getOwnState());
  }
  onIncrement() {
    store.dispatch(Actions.increment(this.props.caption));
  }
  onDecrement() {
    store.dispatch(Actions.decrement(this.props.caption));
  }
}

推荐阅读