React-Navigation Integration with Redux

Dependencies

{
  "dependencies": {
    "@expo/samples": "2.1.1",
    "@shoutem/ui": "0.23.6",
    "expo-asset": "~1.1.0",
    "expo-constants": "~1.0.2",
    "expo-file-system": "~1.1.0",
    "expo-font": "~1.1.0",
    "na": "0.0.1-dev0",
    "prop-types": "15.6.2",
    "react-navigation": "^3.0.9",
    "react-navigation-redux-helpers": "2.0.9",
    "react-navigation/NavigationTestUtils": "3.0.9",
    "react-redux": "6.0.0",
    "react-test-renderer": "16.7.0",
    "redux": "4.0.1"
  }
}
import React from 'react';
import { Platform } from 'react-native';
import {
  createStackNavigator,
  createBottomTabNavigator,
} from 'react-navigation';
import { createStore, applyMiddleware, combineReducers } from 'redux';
import { Provider, connect } from 'react-redux';
import {
  reduxifyNavigator,
  createReactNavigationReduxMiddleware,
  createNavigationReducer,
} from 'react-navigation-redux-helpers';
 
import TabBarIcon from '../components/TabBarIcon';
import HomeScreen from '../screens/HomeScreen';
import ScoresScreen from '../screens/ScoresScreen';
import SearchScreen from '../screens/SearchScreen';
import SettingsScreen from '../screens/SettingsScreen';
import Colors from '../constants/Colors';
import Reducers from '../reducers';
 
/*
const HomeStack = ...
const SearchStack = ...
const ScoresStack = ...
const SettingsStack = ...
*/
 
/* Step 1: create a navigation object */
const AppNavigator = createBottomTabNavigator(
  {
    SearchStack,
    HomeStack,
    ScoresStack,
    SettingsStack,
  },
  {
    tabBarOptions: {
      style: {
        paddingBottom: 5,
      },
      activeTintColor: Colors.tintColor,
    },
  }
);
 
/* Step 2: prepare reducers */
const navReducer = createNavigationReducer(AppNavigator);
const appReducer = combineReducers({
  nav: navReducer, // required, handle actions from react-navigation
  reducers: Reducers, // optional, this is your reducers
});
const middleware = createReactNavigationReduxMiddleware(
  'root',
  state => state.nav
);
const App = reduxifyNavigator(AppNavigator, 'root');
const mapStateToProps = state => ({
  state: state.nav,
});
 
const AppWithNavigationState = connect(mapStateToProps)(App);
 
const store = createStore(appReducer, applyMiddleware(middleware));
 
/* step 3: create store and wrap with Provider */
class Root extends React.Component {
  render() {
    return (
      <Provider store={store}>
        <AppWithNavigationState />
      </Provider>
    );
  }
}
 
export default () => <Root />;
 

Then everything for index are done.

Reducers Example

const defaultState = {
  xxx: 123,
};
 
const reducer = (state, actionData) => {
  let rv = !state ? defaultState : state;
 
  console.log(actionData);
 
  switch (actionData.type) {
    /* Action Item Panel */
    case 'PANEL_ACTIONITEM_DISPLAY': {
      return {
        xxx: state.xxx + 1,
      };
    }
    case 'PANEL_ACTIONITEM_FORM_CHANGE': {
      break;
    }
    case 'PANEL_ACTIONNOTE_FORM_CHANGE': {
      break;
    }
    case 'PANEL_ACTIONNOTE_REQUEST': {
      break;
    }
    default: {
      return rv;
    }
  }
};
 
export default reducer;
 

Actions Example

export const actionItem_ShowEditPanel = () => ({
  type: 'PANEL_ACTIONITEM_DISPLAY',
});   

Actual Usage in Container Components

import React from 'react';
import { ScrollView, StyleSheet, View, TouchableOpacity } from 'react-native';
import { connect } from 'react-redux'
 
import * as actions from '../actions'
 
const mapStateToProps = state => state;
 
const mapDispatchToProps = dispatch => ({
  showActionItemEditRow: (action, data) => dispatch(actions.actionItem_ShowEditPanel()),
})
 
class SearchScreen extends React.Component {
  // hide header from react-navigation
  static navigationOptions = {
    title: null,
    header: null,
  };
 
  render() {
    return (
      <Screen>
        <TouchableOpacity onPress={this.props.showActionItemEditRow}>
          <Row>
            <Text>123</Text>
          </Row>
        </TouchableOpacity>
      </Screen>
    );
  }
}
 
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(SearchScreen);