一、基本概念
action
dispatcher:接受actions,每个application中只有一个dispatcher.
store:管理application的数据。每个store都在dispatcher中进行注册,并接受actions。store中的数据改变时,会触发change事件。每个application中有多个store. store中只能设置getters,不能有setter,但可以设置内置方法,如_add().
view:视图,通常对应React。当view使用一个store中的数据时,必须对store的change事件进行监听。当发生用户交互时,触发相应的action.
二、 以facebook flux + React为例进行说明。
const React = require('react'); const ReactDOM = require('react-dom'); const Dispatcher = require('flux').Dispatcher; const dispatcher = new Dispatcher(); const Store = require('flux/utils').Store; class MyStore extends Store { constructor(dispatcher) { super(dispatcher); this.list = []; } __onDispatch (action) { switch(action.type) { case 'add': this.list.push(action.data); console.log('1', this.list);
// 手动触发事件 this.__emitter.emit('change'); break; default: this.data += 'in the default' } } } var store = new MyStore(dispatcher); class ContainerUI extends React.Component { constructor(props) { super(props); this.state = { list: [] } } handleClick () { dispatcher.dispatch({ type: 'add', data: ReactDOM.findDOMNode(this.refs.input).value }) } componentDidMount () { this.remove = store.addListener(() => { console.log('2') this.setState({ list: store.list }) }) } componentWillUnmount () { this.remove(); } render () { let list = this.state.list.map(item => <li key={item}>{item}</li>); return <ul> <li> <input type='text' ref='input' defaultValue='' /> <button onClick={ this.handleClick.bind(this) }> add </button> </li> {list} </ul> } } export default ContainerUI;
效果如下:
此外,facebook flux中还提供了reduceStore API
import React from 'react'; const Store = require('flux/utils').ReduceStore; const Dispatcher = require('flux').Dispatcher; const dispatcher = new Dispatcher(); class MyStore extends Store { // ReduceStore中需要重写以下两个方法: getInitialState () { return { year: 2020, month: 2, date: 26 } } // 返回一个State reduce(oldState, action) { switch (action.type) { case 'add': return { year: 2020, month: 2, date: oldState.date + 1 } default: return oldState } } } const store = new MyStore(dispatcher); class ContainerUI extends React.Component { handleClick () { dispatcher.dispatch({ type: 'add' }) } componentDidMount () { this.remove = store.addListener(() => { console.log(store.getState()) }) } componentWillUnmount () { this.remove(); } render () { return <ul> <li> <button onClick={ this.handleClick.bind(this) }> new day comes!</button> </li> </ul> } } export default ContainerUI;