用过React开发过项目的可能对Redux都有一定的了解吧,他和Vue中的Vuex也是比较类似的,今天这里就说说如何在RN项目中将Redux和React-Navigation进行结合集成到项目中进行开发:
注意: 由于上次说过React-Navigation,这里就默认看这篇文展是已经了解了React-Navigation的
yarn add redux react-redux react-thunk react-navigation-redux-helpers
// 创建路由相关
import {createAppContainer} from "react-navigation";
import {createStackNavigator} from "react-navigation-stack";
// 配置redux相关
import {createReactNavigationReduxMiddleware, createReduxContainer} from "react-navigation-redux-helpers";
import { connect } from "react-redux";
// 引入路由页面
import WelcomePage from "../page/WelcomePage";
import HomePage from "../page/HomePage";
import DetailPage from "../page/DetailPage";
// 创建路由
const MainNavigator = createStackNavigator({
WelcomePage: {
screen: WelcomePage,
navigationOptions: {
header: null
}
},
HomePage: {
screen: HomePage,
navigationOptions: {
header: null
}
},
DetailPage: {
screen: DetailPage
}
})
// 这两个导出将会在创建导航的reducer中用到, rootCom为初始化的页面路由名, RootNavigator为使用createAppNavigator包装后创建出的路由导航(这是React-Navigation 3.x之后需要做的事情)
export const rootCom = "WelcomePage";
export const RootNavigator = createAppContainer(MainNavigator);
/**
* react-native引入redux中间件第一步
* 创建一个middleware,将navigation引入到store, key为'root'
*/
export const middleware = createReactNavigationReduxMiddleware(
state => state.nav,
'root'
)
/**
* react-native引入redux中间件第二步
*/
const AppWithNavigationState = createReduxContainer(RootNavigator, 'root')
/**
* react-native引入redux中间件第三步
* state 到 Props的映射
*/
const mapStateToProps = state => ({
state: state.nav
})
/**
* react-native引入redux中间件第四步
* 连接React 组件与 Redux store
*/
export default connect(mapStateToProps)(AppWithNavigationState)
import React from "react";
// 从react-redux引入Provider
import {Provider} from "react-redux";
// App路由导航
import AppNavigator from "./navigator/AppNavigator";
// redux store,之后会进行创建
import store from "./store";
export default class App extends React.Component {
render(){
return (<Provider store={store}>
<AppNavigator />
</Provider>)
}
}
// 引入创建store方法和中间件方法
import {applyMiddleware, createStore} from "redux";
import thunk from "redux-thunk";、
// 相关的reducer,这里会使用combineReducer合并多个reducer
import reducers from "../reducer";
// 引入在AppNavigation.js中创建的middleware
import {middleware} from "../navigator/AppNavigator";
/**
* 自定义redux中间件: 用于redux中的dispatch(action)状态进行打印日志
*/
const logger = store => next => action => {
if(typeof action === "function"){
console.log("dispatch a function")
}else {
console.log("dispatch ", action)
}
const result = next(action);
console.log("nextState", store.getState())
}
// 使用的中间件
const middlewares = [
middleware,
logger,
thunk
]
export default createStore(reducers, applyMiddleware(...middlewares))
// 用于合并多个reducer
import {combineReducers} from "redux";
// 这个是之后自己创建的reducer, 和在react web项目中使用创建是一样的
import theme from "./theme";
// 导入Navigatr中的相关内容,用于创建与路由相关的store
import {rootCom, RootNavigator} from "../navigator/AppNavigator";
/**
* 1. 指定默认的state
*/
const navState = RootNavigator.router.getStateForAction(RootNavigator.router.getActionForPathAndParams(rootCom))
/**
* 2. 创建自己的navigation reducer
*/
const navReducer = (state = navState, action) => {
const nextState = RootNavigator.router.getStateForAction(action, state);
return nextState || state;
}
/**
* 3. 合并reducer
*/
const index = combineReducers({
nav: navReducer,
theme: theme
})
export default index
到这里为止就基本可以在各个页面中使用和react web项目相似的方法在各个页面中使用redux的内容了,这里再加一点就是在页面中处理物理返回键
// 这个用于在处理物理返回键时返回上一页
import {NavigationActions} from "react-navigation";
import {
BackHandler
} from "react-native";
// ... 其余省略
// 在组件HomePage中添加如下两个生命周期方法
class HomePage extends React.Component {
// ...
// 处理安卓的物理返回键返回上一页而不是直接返回桌面
componentDidMount(){
BackHandler.addEventListener("hardwareBackPress", this.onBackPress);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.onBackPress);
}
onBackPress = () => {
const {dispatch, nav} = this.props;
// 这里的[0] 或者 1 是根据自己的页面Navigation中页面的次序和当前跳转的层数来的,根究实际情况而定
if(nav.routes[0].index === 1) {
return false;
}
dispatch(NavigationActions.back());
return true;
}
// ... render也省略
}
// 需要将注入到store中的nav注入到组件Props中才可以正常使用
const mapStateToProps = state => ({
nav: state.nav
})
export default connect(mapStateToProps)(HomePage);
Over !!!