Flux
单向数据流的架构模式(在 MVC 中属于M层)
╔═════════╗ ╔════════╗ ╔═════════════════╗
║ Actions ║──────>║ Stores ║──────>║ View Components ║
╚═════════╝ ╚════════╝ ╚═════════════════╝
^ │
└──────────────────────────────────────┘
基于单向数据流如何更好的管理数据,在 Views 与数据之间进行解耦 ,Store 是关键
- View 层 Dispatch actions(分发操作)
- Store 响应action,触发 change事件
- View 层响应change事件
在flux思想之上,有很多优秀的库,比如:reflux,redux
Reflux
下载包:
> npm install reflux --save
Action:定义方法
var Reflux=require("reflux"); module.exports=Reflux.createActions([ "listXxx", "getXxx", "updateXxx", "createXxx", ... ])
Store:监听actions
//xxx-store.jsx var Reflux=require("reflux"); var Api=require("../utils/api"); var xxxActions=require("../actions/xxx-action"); module.exports=Reflux.createStore({ listenables:[XxxActions], // 监听actions data:{}, //添加Action中定义的同名函数 listXxx:function(){ return Api.get("...") .then(function(json){ if(json && json.success) this.data=json.data; this.trigger(this.data,json); //触发(监听此Store的Components会接收到) }.bind(this)); }, ... //也可添加Store自己的函数 });
Component: 调用Action(会触发调用相应的Store方法)或Store方法,监听Store变化
var Reflux=require("reflux"); var XxxActions=require("../action/xxx-action"); var XxxStore=require("../stores/xxx-store"); module.exports=React.createClass({ //监听Store,捕获到则调用onChange方法(相当于callback) mixins:[Reflux.listenTo(XxxStore,"onChange")], onChange:function(data,result){ this.setState({...}); }, componentWillMount:function(){ XxxActions.listXxx(); }, ... });
Redux
中文文档 | Redux 介绍 | 解读redux工作原理
(图片来自:http://staltz.com/unidirectional-user-interface-architectures.html)
store 是一个单一对象:
store.getState()
:获取reducer的root statestore.dispatch(action)
: 向所有reducer分发actionstore.subscribe(listener)
:注册 state 变化监听器createStore(reducer, [initialState])
创建Store
下载包:
> npm install redux --save
> npm install react-redux --save
基本使用示例
Component
var React=require("react"); var ReactDOM=require("react-dom"); var Counter=React.createClass({ render:function(){ return ( <div> <span>{this.props.value}</span> <button className="btn btn-default" onClick={this.props.onIncreaseClick}>Increase</button> </div> ) } });
Store
var redux=require("redux"); var countRedux=function(state,action){ switch(action.type){ case 'INCREASE': return state+action.step; } return state; } var store=redux.createStore(countRedux,0); store.subscribe(function(){ console.log(store.getState()); });
Action
var increaseAction={type:'INCREASE',step:1}; //test store.dispatch(increaseAction);
Container
var Provider=require("react-redux").Provider; var connect=require("react-redux").connect; //Map Redux state to component props function mapStateToProps(state){ return {count:state} } //Map Redux dispatch to component props function mapDispatchToProps(dispatch){ return { onIncreaseClick:function(){dispatch(increaseAction);} } } var App=connect(mapStateToProps,mapDispatchToProps)(Counter) // render ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('app') );
高阶使用示例
(图片来自:https://www.udemy.com/react-redux/ 教程)
要点:
- Reducer:
var bookReducer=function(state,action){...}; var activeBookReducer=function(state,action){...}; module.exports=combineReducers({ books:booksReducer, activeBook:activeBookReducer })
Action Creator:
var selectBook=function(book){ console.log("Selectd:"+book.title); return {type:"BOOK_SELECTED",payload:book}; } module.exports={ selectBook:selectBook }
Container:
var bindActionCreators=require("redux").bindActionCreators; function mapDispatchToProps(dispatch){ /*return { selectBook:function(book){dispatch({type:'BOOK_SELECTED',payload:book})} }*/ return bindActionCreators(BookActions,dispatch); }
可使用middleware实现异步Action (例如使用redux-promise
)
(图片来自:https://www.udemy.com/react-redux/ 教程)
要点: 触发action,传递promise对象,使用middleware拦截直到响应,继续传递action到reducers
下载包
redux-promise
(Redux Middleware) &axios
(Promise Request):> npm install redux-promise --save > npm install axios --save
Action:
{type:'BOOK_LIST',payload:axios.get(url);}
Reducer:
var booksReducer=function(state,action){ switch(action.type){ case 'BOOK_LIST': if(action.payload.status==200){ return [action.payload.data]; } } return state; }
Store
var createStore=require("redux").createStore; var applyMiddleware=require("redux").applyMiddleware; var ReduxPromise=require("redux-promise"); var createStoreWithMiddleware=applyMiddleware(ReduxPromise)(createStore); var store=createStoreWithMiddleware(booksReducers);