React-Navigation與Redux整合詳解
繼react-navigation釋出已經過去半年的時間,想必React Native的玩家早已玩轉於手掌了。如果你還不瞭解,就out啦~還在等什麼?
Redux框架給開發者帶來的優勢是顯而易見的。它好比Android中的MVP架構一樣,使得複雜的業務邏輯和檢視狀態變得簡單、清晰。如何將react-navigation和Redux結合到一起呢?本篇部落格就來嘮嘮。
在搞定Redux與react-navigation整合之前,我們有必要先了解下在沒有使用react-navigation導航下的Redux專案架構,先來看一個簡單的Redux專案目錄:
一般情況下,Redux專案中都會包含如下幾個目錄:
(1)Action
(2)Reducer
(3)Store
熟悉Redux的玩家肯定對這三個模組肯定都不陌生。Action中負責分發使用者行為;Reducer接收Action,並根據行為型別進行相應的邏輯處理,並返回最新狀態;Store中負責Action和Reducer的互動,並記錄Reducer處理的最新狀態。並且還可以應用中介軟體等;此時可利用react-redux將狀態與檢視繫結。這樣,Action -> Controller -> View就完美的形成了閉環流程。下面我們分別看下三者之間是如何銜接的。
1、Action
export let main = (url, params, isLoading, isLoadMore, isRefreshing) => {
return dispatch => {
// 1.發出拉取資料的訊號
dispatch(loadMainContent(isLoading, isLoadMore, isRefreshing));
// 2.請求網路
return HttpUtil.fetchGet(url, params,
(responseObj) => {
dispatch(receiveMainContent(responseObj.result.bookList));
console .info("success");
},
(error) => {
dispatch(receiveMainContent([]));
console.info("error" + error);
}
)
}
}
let loadMainContent = (isLoading, isLoadMore, isRefreshing) => {
return {
type: types.LOAD_MAIN_LIST,
isLoading: isLoading,
isLoadMore: isLoadMore,
isRefreshing: isRefreshing
}
}
let receiveMainContent = (mainList) => {
return {
type: types.GET_MAIN_LIST,
mainList: mainList
}
}
如上程式碼所示,在main Action中,我們定義了不同的Action行為,並通過dispatch進行分發。
2、Reducer
const initState = {
mainList: [],
isLoading: true,
isLoadMore: false,
isRefreshing: false
}
let mainReducer = (state = initState, action) => {
switch (action.type) {
case types.LOAD_MAIN_LIST:
return Object.assign({}, state, {
isLoading: action.isLoading,
isLoadMore: action.isLoadMore,
isRefreshing: action.isRefreshing
});
case types.GET_MAIN_LIST:
return Object.assign({}, state, {
isLoading: false,
isRefreshing: false,
mainList: state.isLoadMore ? state.mainList.concat(action.mainList) : action.mainList
})
default:
return state;
}
}
上面程式碼定義了對應的Reducer,用來接收Action的行為,並進行處理,最終返回最新狀態State。
3、整合Reducer
export default rootReducer = combineReducers({
Main,
})
4、Store
let store = createStore(rootReducer, {}, compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : f => f
))
Store相對簡單,因為Redux本身沒有非同步概念,不能直接使用setTimeOut等,但是網路處理需要非同步進行,並且結果是非同步返回,所以為了處理此種情況,可以使用中介軟體react-thunk幫助我們完成。
5、Connect
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import App from './components/app';
import store from './store/store';
export default class Root extends Component {
render() {
return (
<Provider store={store}>
<App />
</Provider>
)
}
}
使用react-redux將store傳遞到Provider,從而將Redux和檢視層繫結在一起,完成Action -> Reducer -> Store -> View的整體連線。
上面程式碼中App即檢視的入口,react-navigation其實就充當了程式的入口,負責檢視介面之間的跳轉互動。
const AppNavigator = StackNavigator( { Splash: { screen: SplashScene }, } )
在react-navigation中使用navigate來實現介面間跳轉行為。此時我們可以理解為Redux中的dispatch,即一個使用者行為。
1、dispatch的觸發需要Reducer的接收,所以我們需要定義react-navigation的Reducer:
import Routers from './Router';
const navReducer = (state,action) => {
const newState = Routers.router.getStateForAction(action, state);
return newState || state;
}
export default navReducer;
Router中就是我們定義的react-navigation的StackNavigator。navReducer即為接收跳轉狀態的Reducer,程式碼中我們通過獲取StackNavigator的Action來返回最新的處理狀態。
2、在rootReducer中註冊該reducer:
export default rootReducer = combineReducers({
Nav
})
3、Store中仍然是註冊rootRecuder,使用中介軟體等等。
4、App首頁中繫結(app.js)
@connect(state => ({
nav: state.nav
}))
class AppWithNavigationState extends Component {
render() {
return (
<Router
navigation={addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav
})}
/>
);
}
}
export default class App extends Component {
render() {
return(
<Provider store={ store }>
<AppWithNavigationState/>
</Provider>
)
}
}
以上程式碼定義在程式入口中,從程式碼可以看到,首先使用@connect繫結nav的state,即NavReducer中返回的state。Router就是我們的StackNavigator,對其新增addNavigationHelpers,並將dispatch和state傳入。dispatch和nav就是Redux中分發的行為和狀態,這樣去觸發react-navigation的改變。最後使用Provider包含並將store注入到Provider。
總結下流程:
(1)定義navReducer,返回導航狀態。(跳轉State)
(2)註冊reducer。 (將navReducer新增到rootReducer)
(3)建立store。(store中注入rootReducer)
(4)程式入口中將store注入Provider。(Provider將store注入StackNavigator)
(5)@connect獲取最新導航狀態。(將StackNavigator於=與Redux繫結)
(6)設定StackNavigator的addNavigationHelpers,並將狀態和行為傳入。(StackNavigator接收到Reducer返回的最新狀態,執行相應改變(跳轉等))
以上步驟執行完,此時,程式會在@connect丟擲錯誤,因為我們使用了@描述符,所以需要引入如下第三方庫:
"babel-plugin-transform-decorators-legacy": "^1.3.4"
(1)npm i babel-plugin-transform-decorators-legacy --save -dev
(2)專案根目錄找到檔案,開啟新增如下:
{
"presets": ["react-native"],
"plugins":["transform-decorators-legacy"] // 新增引用外掛
}
ok,到此通過以上步驟,我們就將Redux和react-navigation整合在一起啦~
老規矩,原始碼奉上, 點選下載
剛建立的 React Native交流11群:112490774 ,歡迎各位大牛,React Native技術愛好者加入交流!同時部落格右側歡迎微信掃描關注訂閱號,移動技術乾貨,精彩文章技術推送!
尊重原創,轉載請註明:From Sky丶清(http://www.lcode.org) 侵權必究!