學(xué)過React Native的都知道,RN的UI是根據(jù)相應(yīng)組件的state進(jìn)行render的,而頁面又是由大大小小的組件構(gòu)成,導(dǎo)致每個(gè)組件都必須維護(hù)自身的一套狀態(tài),因此當(dāng)頁面復(fù)雜化的時(shí)候,管理state會(huì)相當(dāng)吃力的。而redux提供了一套機(jī)制來組織管理整個(gè)應(yīng)用狀態(tài)。
? ? ? ?Redux有三部分組成:store,action,reducer。
? ? ? ?store:維護(hù)全局的state,以及將action和reducer結(jié)合起來。
? ? ? ?action:用來傳遞state的信息。(比如:我們?cè)赼ction中處理登陸操作,將返回的user對(duì)象傳遞給對(duì)應(yīng)的reducer.)
? ? ? ?reducer:reducer是簡(jiǎn)單的處理函數(shù),通過傳入舊的state和指示操作的action來更新state,從而達(dá)到頁面的刷新。
下面通過一個(gè)簡(jiǎn)單的例子來集成下。
首先安裝相關(guān)庫:
?
安裝redux:npm install --save redux
安裝redux綁定庫:npm install --save react-redux
安裝開發(fā)者工具:npm install --save-dev redux-devtools
安裝異步action構(gòu)造器:npm install --save redux-thunk
在集成之前熟悉下一般基于Redux的目錄結(jié)構(gòu):
?
. ├── src #開發(fā)目錄 | | | ├──constants #ActionTypes和Urls | | | ├──actions #actions的文件 | | | ├──components #內(nèi)部組件 | | | ├──containers #容器組件 | | | ├──reducers #reducer文件 | | | ├──stores #store配置文件 | | | └──utils #工具 | ├── node_modules #包文件夾 ├── .gitignore ├── index.js #入口文件 └── package.json
(如果你之前不了解Redux的話,或許會(huì)比較蒙圈,但不要緊,跟著流程多走幾遍,試著推敲先分析下流程,慢慢就理解了)
/*************************************store*************************************/
1.首先創(chuàng)建全局的store。(一般在stores文件中寫個(gè)配置文件)
?
[javascript]?view plain
?copy 'use?strict';????import?{?createStore,?applyMiddleware?,combineReducers}?from?'redux';??import?thunk?from?'redux-thunk';import?*?as?reducers?from?'../reducers';??const?middlewares?=?[thunk];????const?createSoreWithMiddleware=applyMiddleware(...middlewares)(createStore);????export?default?function?configureStore(initialState){????????const?reducer=combineReducers(reducers);??????const?store=createSoreWithMiddleware(reducer,initialState);????????return?store;??}?? 簡(jiǎn)單講解下:
首先引入該APP中所有的reducer,根據(jù)上面的目錄結(jié)構(gòu),我們把所有的reducer放入到reducers文件中,切記要加入個(gè)index.js進(jìn)行配置.上面很多都是固定格式,暫時(shí)先不分析為什么,做的目的就是返回一個(gè)全局的store.
store的應(yīng)用(這里的APP就是我們應(yīng)用的最頂層組件)。
?
[javascript]?view plain
?copy import?React,?{?Component?}?from?'react';??import?{Provider}?from?'react-redux';??import?App?from?'./containers/app';????import?configureStore?from?'./store/configureStore';??const?store=configureStore();??export?default?class?Root?extends?Component{?????render(){???????return(?????????<Provider?store={store}>?????????<App/>?????????</Provider>???????);?????}??}?? App組件其實(shí)可以把所有的頁面加入到這里,全局進(jìn)行控制(官方F8是這么操作的)。不過這里暫時(shí)先不這樣處理,關(guān)于navigator的push,pop操作還是放到對(duì)應(yīng)的頁面進(jìn)行處理,更符合我們的原生開發(fā)邏輯。
簡(jiǎn)單看下store中結(jié)構(gòu):
?
/*************************************action*************************************/
創(chuàng)建登陸對(duì)應(yīng)的action:
?
[javascript]?view plain
?copy ?import?*?as?types?from?'./types';???import?{Alert}from?'react-native';????export?function?login(user){?????return?dispatch=>{????????????dispatch({type:types.LOGIN_ING});???????let?result=fetch('http://www.baidu.com')??????????????????.then((res)=>{??????????????????????????????????????setTimeout(()=>{??????????????????????if(user.phone=='15221850400'&&user.password=='123456'){????????????????????????dispatch({type:types.LOGIN,user:user});??????????????????????}else{??????????????????????????????????????????????Alert.alert('用戶名或密碼錯(cuò)誤');??????????????????????????dispatch(error());??????????????????????}????????????????????},1000);??????????????????}).catch((err)=>{?????????????????????alert(err);?????????????????????dispatch({type:types.LOGIN_ERROR});??????????????????})?????}??}????function?error(){????return?{??????type:types.LOGIN_ERROR????};??}????export?function?logout(){????return?{??????type:types.LOGOUT,????};??}?? 邏輯還算簡(jiǎn)單,就只是做個(gè)用戶名,密碼判斷,但或許會(huì)問dispatch是個(gè)什么玩意,哪來的呢,其實(shí)上面我們也截圖出來了,這個(gè)方法是我們創(chuàng)建全局store中的方法。
至于action正常的應(yīng)該只是一個(gè)含有type的json對(duì)象,但是為了擴(kuò)展性,一般會(huì)寫成函數(shù)的形式,俗稱action creator如上面的logout方法.
至于login方法由于需要網(wǎng)絡(luò)操作,固然是異步的,就好比我們?cè)_發(fā)的時(shí)候請(qǐng)求API的操作一般都會(huì)丟到一個(gè)線程中,通過Handler消息機(jī)制來渲染UI.
dispatch({type:types.LOGIN_ING}):根據(jù)相應(yīng)的action來進(jìn)行調(diào)用對(duì)應(yīng)reducer方法。
/*************************************reducer*************************************/
接著我們看下最后一個(gè)reducer:
?
[javascript]?view plain
?copy import?*?as?types?from?'../actions/types';????const?initialState={????isLoggedIn:false,??user:{},????status:?null,};????export?default?function?user(state=initialState,action={}){??????switch(action.type)?{??????case?types.LOGIN:?????????return{???????????...state,???????????isLoggedIn:true,???????????user:action.user,???????????status:?'done',?????????}????????break;??????case?types.LOGIN_ING:????????return?{??????????...state,??????????isLoggedIn:false,??????????status:?'doing',????????}????????break;??????case?types.LOGIN_ERROR:??????console.log('types.LOGIN_ERROR...');??????????return{????????????...state,??????????????isLoggedIn:?false,????????????status:?null,??????????};??????????break;??????case?types.LOGOUT:??????????return?{??????????...state,??????????isLoggedIn:false,??????????status:null,????????}????????break;??????????default:????????return?state;????}??}?? reducer其實(shí)就是根據(jù)一系列action的處理函數(shù),好比我們?cè)谇懊鎍ction中返回的有LOGIN,LOGIN_ING,LOGIN_ERROR等狀態(tài),然后調(diào)用reducer根據(jù)不同的type返回當(dāng)前最新的state,然后再render ui。
/*************************************connect*************************************/
redux的三部分至此就操作完畢,但如果進(jìn)行鏈接起來呢,這里就用到connect組件,connect是將某一個(gè)組件(這里一般指一個(gè)頁面)和store鏈接起來,目的就是獲取當(dāng)前頁面所需的state以及dispatch方法。(從全局state中獲取這個(gè)頁面需要的數(shù)據(jù)然后以props的形式傳遞給當(dāng)前頁面。)
?
[javascript]?view plain
?copy import?React,?{?Component?}?from?'react';??import?{????StyleSheet,????TextInput,????Text,????View,????TouchableHighlight,????ActivityIndicator,??}?from?'react-native';????import?{connect}?from?'react-redux';import?{bindActionCreators}?from?'redux';import?*?as?actionCreators?from?'../actions/loginActions';import?Modal?from?'react-native-modalbox';??import?Home?from?'./home';??????class?Login?extends?Component{??????constructor(props){??????super(props);????????this.state={??????}????????this.login=this.login.bind(this);??????this.onChangePhone=this.onChangePhone.bind(this);??????this.onChangePswd=this.onChangePswd.bind(this);????}???????onChangePhone(text){???????this.setState({'phone':text,});?????}???????onChangePswd(text){???????this.setState({'password':text,});?????}???????login(){?????????if(!this.state.phone||!this.state.password){?????????alert('用戶名或密碼不能為空!');???????}else{?????????this.refs.modal.open();???????this.props.actions.login({'phone':this.state.phone,'password':this.state.password});?????}?????}??????????shouldComponentUpdate(nextProps,nextState){???????const?{isLoggedIn,navigator}=nextProps;????????if(isLoggedIn){??????????this.setState({phone:'',password:''});????????????navigator.push({????????????component:Home,????????????name:'Home',??????????});????????}???????return?true;?????}???????render(){??????console.log('render...');???????return(????????<View?style={{flex:1}}>????????<View?style={{padding:20,marginTop:50}}>????????<View?style={styles.item}><Text?style={{width:70}}>手機(jī)號(hào)碼</Text>????????<TextInput????????style={styles.input}????????onChangeText={this.onChangePhone}????????placeholder='請(qǐng)輸入手機(jī)號(hào)碼'????????value={this.state.phone}????????/>????????</View>????????<View?style={styles.item}>????????<Text?style={{width:70}}>密碼</Text>????????<TextInput????????style={styles.input}????????onChangeText={this.onChangePswd}????????placeholder='請(qǐng)輸入密碼'????????password={true}????????value={this.state.password}????????/>????????</View>??????????<TouchableHighlight?style={styles.button}?????????underlayColor='#000000'?onPress={this.login}>????????<Text?style={{fontSize:16,color:'#fff'}}>登陸</Text>????????</TouchableHighlight>????????</View>??????????<Modal????????style={styles.modal}????????ref='modal'????????isOpen={this.props.status=='doing'?true:false}????????animationDuration={0}????????position={"center"}????????>????????<ActivityIndicator????????size='large'????????/>????????<Text?style={{marginTop:15,fontSize:16,color:'#444444'}}>登陸中...</Text>????????</Modal>????????</View>???????);?????}??}????const?styles?=StyleSheet.create({??????item:{????????flex:1,????????flexDirection:'row',????????alignItems:'center',????????height:50,????????borderBottomColor:'#ddd',????????borderBottomWidth:1,??????},??????input:{????????flex:1,????????fontSize:14,??????},??????button:{????????backgroundColor:'#1a191f',????????height:50,????????marginTop:40,????????justifyContent:'center',????????alignItems:'center'??????},??????modal:?{????????justifyContent:?'center',????????alignItems:?'center',????????width:150,????????height:150,????????borderRadius:10,??????},??});????function?mapStateToProps(state){????return{??????isLoggedIn:state.user.isLoggedIn,??????status:state.user.status,????};??}??function?mapDispatchToProps(dispatch){????return?{????????actions:?bindActionCreators(actionCreators,?dispatch)????};??}????export?default?connect(mapStateToProps,mapDispatchToProps)(Login);?? 上面的代碼不用仔細(xì)看,主要是尾部的部分,
mapStateToProps方法:根據(jù)全局state返回當(dāng)前頁面所需的數(shù)據(jù)然后以props的形式傳遞給當(dāng)前頁面(Login)。
mapDispatchToProps:該方法就是將dispatch和當(dāng)前頁面引入的actionCreators綁定在一起,然后就可以輕松調(diào)用。
如:login方法中的:
this.props.actions.login({'phone':this.state.phone,'password':this.state.password});//dispath 登陸
?
這樣整體集成就完畢了,這里簡(jiǎn)單總結(jié)下:
1.首先我們創(chuàng)建全局的store(基于所有的reducer)在APP最外層引用,然后我們創(chuàng)建action(可以根據(jù)頁面或者某種類別來定義)。接著我們創(chuàng)建reducer(可以設(shè)計(jì)成跟action一一對(duì)應(yīng))。最后通過connect將它們和頁面鏈接起來,至于action和reducer的內(nèi)容,可以等頁面編輯OK后再進(jìn)行設(shè)計(jì)。
2.執(zhí)行簡(jiǎn)單流程:在頁面中首先調(diào)用對(duì)應(yīng)action方法(傳遞參數(shù))--->執(zhí)行相應(yīng)的業(yè)務(wù)邏輯,然后調(diào)用dispatch(action)(將結(jié)果以action的形式傳遞給reducer)--->在reducer中根據(jù)type字段然后返回最新的state,然后在進(jìn)行render具體的ui。
?
引用原文:https://blog.csdn.net/jj120522/article/details/52071469
可以參考:https://www.jianshu.com/p/4139babc6d5e
?
寫博客是為了記住自己容易忘記的東西,另外也是對(duì)自己工作的總結(jié),文章可以轉(zhuǎn)載,無需版權(quán)。希望盡自己的努力,做到更好,大家一起努力進(jìn)步!
如果有什么問題,歡迎大家一起探討,代碼如有問題,歡迎各位大神指正!
轉(zhuǎn)載于:https://www.cnblogs.com/summary-2017/p/8626414.html
總結(jié)
以上是生活随笔為你收集整理的React Native集成Redux框架讲解与应用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。