Skip to content

Latest commit

 

History

History
192 lines (164 loc) · 5.73 KB

ReactNavigation集成Redux.md

File metadata and controls

192 lines (164 loc) · 5.73 KB
title date tags
React Navigation 集成 Redux
2017年12月7日21:54:53
React Native
Redux

更新时间:2018-03-03

修复因 React Navigation 更新引起的 addListener is not a function 的问题。


react-navigation 是 React Native 官方推荐的导航库。redux 是一个状态容器,redux 的简单使用可参考阮一峰的 Redux 入门教程,现在网上也有很多中文文档。

在 React Navigation 最新版本中需要添加 react-navigation-redux-helpers

$ yarn add react-native-navigation-redux-helpers
# 或者 npm install --save react-native-navigation-redux-helpers

首先写 redux helper 工具 redux.js

import {
    createReactNavigationReduxMiddleware,
    createReduxBoundAddListener
} from 'react-navigation-redux-helpers';

// 注意: createReactNavigationReduxMiddleware 必须在 createReduxBoundAddListener 之前执行
const middleware = createReactNavigationReduxMiddleware('root', state => state.nav,);

const addListener = createReduxBoundAddListener('root');

export {
    middleware,
    addListener
};

首先写一个 navigator

export const AppNavigator = StackNavigator({
    Home: { screen: HomeTab },  // 这是一个 TabNavigator
    Details: { screen: DetailPage },  // 简单的页面
  });

集成 Redux 主要含三部分:Store,Action,Reducer

Redux

Action

export function getBanners() {
    return dispatch => {
        // request 是我自己封装的网络请求方法
        request({
            url: apis.BANNER  // 常量 API 地址
        }).then(res => {
            dispatch({
                type: actionTypes.BANNER,  // 常量行为类型
                data: res
            })
        })
    }
}

Reducer

  1. othersReducer.js
// 初始 state
const initState = {
    banners: [],
    articles: [],
    loading: false
}

export default function discoveryData(state=initState, action) {
    switch(action.type) {
        case actionTypes.BANNER:
            return {...state, banners:action.data, loading:false}
        default:
            return state;
    }
}
  1. navReducer.js 用于导航
import { AppNavigator } from '../navigators/AppNavigator';
import { NavigationActions } from 'react-navigation';
// Home 是个 TabNavigator,在这里 firstAction 为 null,会导致后续程序会出错,所以自己手写了一个 action
const firstAction = AppNavigator.router.getActionForPathAndParams('Home') || {
    type: 'Navigation/NAVIGATE',
    touteName: 'Home'
};
const initialNavState = AppNavigator.router.getStateForAction(firstAction);
const navReducer = (state = initialNavState, action) => {
    const nextState = AppNavigator.router.getStateForAction(action, state);
    return nextState || state;
}

export default navReducer;

在以前版本里,我是把 firstAction 和 initialNavState 注释掉了,如果不注释掉会在 getStateForAction 时报 undefined 错误 undefined 解决方案多种: 一种是将 TabNavigator 放在单纯的 Component 中作为 StackNavigator 的 screen,这样就可以使用 initialNavState了,弊端是不方便从其它页面跳转到 TabNavigator 的指定 Tab 页。 另一种就是我现在使用的方案了。 如果你有更好的解决方案请告诉我!!

在新版本中不再出现上述问题,而是出现代码中提到的 null 问题 3. 整合 Reducer

import { combineReducers } from 'redux';
import navReducer from './navReducer';
import othersReducer from './othersReducer';

const AppReducer = combineReducers({
    nav: navReducer,
    othersReducer
});

export default AppReducer;

配置 Store

import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';  // 中间件
import reducers from './../reducers';  // 整合后的 Reducer
import { middleware } from './redux';  // redux helper

const configStore = applyMiddleware(thunkMiddleware, middleware)(createStore)

export default configStore(reducers);

自定义 Navigator

import { connect } from 'react-redux';
import { addNavigationHelpers, NavigationActions } from 'react-navigation';
import { addListener } from './redux';

class AppWithNavigationState extends Component {

  componentDidMount() {
    BackHandler.addEventListener('hardwareBackPress', this.onBackPress)
  }

  componentWillUnmount() {
    BackHandler.removeEventListener('hardwareBackPress', this.onBackPress)
  }

  onBackPress = () => {
    const { dispatch, nav } = this.props;
    dispatch(NavigationActions.back())
    return !(nav.index===0)
  }

  render() {
    return (
      <AppNavigator 
        navigation={addNavigationHelpers({ 
          dispatch: this.props.dispatch,
          state: this.props.nav,
          addListener  // 关键所在
        })} 
      />
    )
  }
}

const mapStateToProps = state => ({
  nav: state.nav,
});

export default connect(mapStateToProps)(AppWithNavigationState);

绑定到应用中

在入口文件中绑定 Redux 的 store 管理库

import { Provider } from 'react-redux';
import store from './src/store';

export default class App extends React.Component {
  render() {
    return (
      <Provider store={store}>
        <AppWithNavigationState />
      </Provider>
    );
  }
}

所有源码我已经放到了 GitHub 查看源码