在react-native開發中關於數據的流向,state的管理及路由解決等問題會隨着項目的複雜讓人越來越頭疼,也讓人力不從心。於是React的開發者推出了Flux架構及官方實現,力圖解決這些問題。Flux框架其核心思想就是單項數據流,Flux的整個流程爲:Action -> Dispatcher -> Store -> View.
當然Flux框架只是一種單向數據流的思想,業界有很多基於Flux的框架,當下最流行的當屬Redux。
Redux的三大定律:1.單一數據源。2.state是隻讀的,改變state的唯一方法就是觸發action,action其實就是一個普通的javascript對象。3.使用純函數執行修改,這裏所說的純函數就是Redux中reducer。
Redux的組成:
1.action
首先要知道action就是一個信息載體,也是一個javascript對象,對象中至少要包括一個動作行爲的唯一標示,比如增刪改查操作。
比如:
userAction.js
import * as constant from '../constants/CommonConstants';
export function updateData(user){
return {
type: constant.UPDATE_DATA,
user: user
};
}
export function requestData(){
return dispatch => {
let url = 'https://my.oschina.net/gef';
fetch(url)
.then((response) =>{
console.log("response:" + response);
return response.text();
})
.then((responseText) => {
console.log("responseText:" + responseText);
if (responseText) {
let user = {
'name' : "葛夫鋒",
'age' : 18,
'job' :'developer'
};
dispatch(updateData(user));
}
})
.catch((error) => {
console.log("error:" + error);
});
};
}
我定義了兩個action,第一個是更新數據的action,第二個是請求數據的action,第二個action所return的其實是一個函數,其參數爲dispatch,然後進行了網絡請求,請求成功之後執行了第一個action。
2.reducer
action定義了要執行的操作,但是沒有規定action執行之後state如何變化,那麼reducer的任務就是定義整個程序的state如何響應。
其實reducer就是一個純函數,例如:
UserReducer.js
import * as constant from '../constants/CommonConstants'
const initState = {
flag:1, //1請求中 2請求成功
user: null
}
export default function addUser(state = initState,action){
switch(action.type){
case constant.LOAD_USER:
return Object.assign({},state,{flag : 1});
case constant.UPDATE_DATA:
return Object.assign({},state,{flag : 2, user : action.user});
default:
return state;
}
}
baseReducers.js
import {combineReducers} from 'redux';
import UserReducer from './UserReducer';
const rootReducer = combineReducers({
UserReducer
});
export default rootReducer;
- 保存整個程序的state
- 通過getState()方法訪問state的值
- 通過dispatch()方法執行一個action
- 通過subscribe(listener)註冊回調,監聽state的變化
例如:
index.ios.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import {
AppRegistry,
} from 'react-native';
import React from 'react';
import {applyMiddleware,createStore} from 'redux';
import thunk from 'redux-thunk';
import {Provider} from 'react-redux';
import Root from './app/root';
import rootReducers from './app/reducers/baseReducers';
var store = createStore(rootReducers,applyMiddleware(thunk));
function App(props){
return (
<Provider store = {store}>
<Root {...this.props}/>
</Provider>
);
};
AppRegistry.registerComponent('ReduxDemo', () => App);
root.js
import React from 'react';
import {View,StyleSheet,Text} from 'react-native';
import {connect} from 'react-redux';
import {requestData,updateData2} from './actions/userAction';
class Root extends React.Component{
render(){
let {flag,user} = this.props;
//flag
let content = null;
if(flag == 1){
content = (<Text>加載中</Text>);
}else{
content = (<Text>加載成功</Text>);
}
//user
let userView = null;
if (user) {
userView = (<View style = {style.userView}>
<Text>姓名:{user.name}</Text>
<Text>年齡:{user.age}</Text>
<Text>工作:{user.job}</Text>
</View>);
}
return (
<View style = {style.container}>
{content}
{userView}
</View>
);
}
componentDidMount(){
let {updateData} = this.props;
updateData();
}
}
const style = StyleSheet.create({
container:{
flex: 1,
alignItems: 'center',
justifyContent:'center',
backgroundColor: '#FF6A6A'
},
userView:{
marginTop:10
}
});
function mapStateToProps(state){
return {
flag:state.UserReducer.flag,
user:state.UserReducer.user
};
}
function mapDispatchToProps(dispatch){
return {
updateData:function(){
dispatch(requestData());
}
};
}
export default connect(mapStateToProps,mapDispatchToProps)(Root);
這裏用到了react-redux庫,用於輔助在React項目中使用Redux,它的API相當簡單,包括一個React Component(Provider)和一個高階方法connect。
這裏還用到了一個middleware,叫做redux-thunk。redux-thunk的存在允許 store.dispatch一個函數,也就是action不是一個javascript對象,而可以是一個函數。
以上代碼例子組合起來就是一個網絡異步加載的小例子,其運行效果如下:
完整代碼:
https://github.com/johngef/Redux-Demo