react-navigation的state管理放到application统一的管理中,即所谓的react-navigation和redux一体化,或者集成。
官网doc介绍:https://reactnavigation.org/docs/redux-integration.html
- 添加依赖
- 编写navReducer
- 如何实现一体化
- 编写Root.js入口组件
- 物理键重写
- Demo地址
添加依赖
yarn add react-navigation-redux-helpers
或
npm install --save react-navigation-redux-helpers
编写navReducer
import {NavigationActions} from 'react-navigation'
import {AppNavigator} from "../AppNavigator";
// Start with two routes: The Main screen, with the Login screen on top.
const firstAction = AppNavigator.router.getActionForPathAndParams('Main');
const tempState = AppNavigator.router.getStateForAction(firstAction);
const secondAction = AppNavigator.router.getActionForPathAndParams('Login');
const initiaNavState = AppNavigator.router.getStateForAction(secondAction,tempState);
function nav(state=initiaNavState,action){
let nextState;
switch (action.type){
case 'Login':
nextState = AppNavigator.router.getStateForAction(
NavigationActions.back(),
state
)
break;
case 'Logout':
nextState = AppNavigator.router.getStateForAction(
NavigationActions.navigate({ routeName: 'Login' }),
state
);
break;
case 'BackTwoScreen':
const key = state.routes[state.index-1].key
nextState = AppNavigator.router.getStateForAction(
NavigationActions.back({key:key}),
state
)
break;
case 'ExitApp':
nextState = initiaNavState;
break;
default:
nextState = AppNavigator.router.getStateForAction(action, state);
break;
}
// Simply return the original `state` if `nextState` is null or undefined.
return nextState || state;
}
export default nav;
在reducers文件夹下创建index.js文件,将多个reducer合并。
import {combineReducers} from 'redux'
import nav from './nav'
import auth from './auth'
const AppReducers = combineReducers({
nav,
auth
})
export default AppReducers;
如何实现一体化
创建AppNavigator.js文件。
import React from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux'
import {addNavigationHelpers,StackNavigator,NavigationActions } from 'react-navigation'
import {addListener} from "./utils/redux";
...
export const AppNavigator = StackNavigator(
{
Login: { screen: LoginScreen },
Main: { screen: MainScreen },
Profile: { screen: ProfileScreen },
ThirdScreen: { screen: ThirdScreen },
}
)
class AppWithNavigationState extends React.Component{
static propTypes = {
dispatch:PropTypes.func.isRequired,
nav:PropTypes.object.isRequired,
}
render(){
const {dispatch,nav} = this.props;
return(
<AppNavigator
navigation = {addNavigationHelpers({
dispatch,
state:nav,
addListener
})}
/>
)
}
}
const mapStateToProps = state =>({
nav:state.nav
})
export default connect(mapStateToProps)(AppWithNavigationState);
其中/utils/redux.js文件内容:
import {
createReactNavigationReduxMiddleware,
createReduxBoundAddListener
} from 'react-navigation-redux-helpers'
const middleware = createReactNavigationReduxMiddleware(
'root',
state => state.nav
)
const addListener = createReduxBoundAddListener('root')
export {
middleware,
addListener,
};
编写Root.js入口组件
import React from 'react';
import {Provider} from 'react-redux'
import {createStore,applyMiddleware} from 'redux'
import AppWithNavigationState from './AppNavigator'
import {middleware} from "./utils/redux";
import AppReducers from './reducers/index'
const store = createStore(AppReducers,applyMiddleware(middleware))
export default class ReduxExampleApp extends React.Component {
render(){
return(
<Provider store = {store}>
<AppWithNavigationState/>
</Provider>
)
}
}
物理键重写
在AppNavigaor.js文件中,进行物理键监听
import React from 'react';
import { BackHandler,ToastAndroid } from "react-native";
import PropTypes from 'prop-types';
...
export const AppNavigator = StackNavigator(
{
Login: { screen: LoginScreen },
...
}
)
class AppWithNavigationState extends React.Component{
...
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this.onBackPress);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.onBackPress);
}
onBackPress = ()=>{
const { dispatch, nav } = this.props;
if (nav.index === 0) {
if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
//将state设置成第一次启动一致,避免从哪个界面退出,
启动时显示哪个界面的bug(杀掉进程启动无该问题)
dispatch({type:'ExitApp'})
return false
}
ToastAndroid.show('再按一次退出!', 1000);
this.lastBackPressed = Date.now();
return true;
}
dispatch(NavigationActions.back());
return true;
}
render(){
const {dispatch,nav} = this.props;
return(
<AppNavigator
navigation = {addNavigationHelpers({
dispatch,
state:nav,
addListener
})}
/>
)
}
}
const mapStateToProps = state =>({
nav:state.nav
})
export default connect(mapStateToProps)(AppWithNavigationState);