How to structure your React Native application using Redux?

Introduction

Eric Kim
4 min readJul 13, 2016

I have worked on production React Native Redux application for the past 5 months, which was supposed to only take 3 month when we first analyzed. We later concluded that this 50% increase was due to poorly structured application which caused a lot of refactoring and duplicated codes. If you are planning to use redux in your react-native application, please read on.

I will assume you have basic knowledge about React Native and Redux, so if you are new to Redux, you can check out my previous post on Redux and come back to this post.

What is React Native?

I would assume you already know the basics about React/React Native, if not please check out the official guide.

What is Redux?

In short, it is both a design pattern and a library. Redux and React-Redux is a small library that helps you follow this design pattern through some restrictions and let you write less boilerplate code. These two libraries are essential when developing React Native application using Redux.

Terminology

I want to list some terminologies and explain what they are here, so you can refer back to here whenever you are lost.

  1. React Component — A JavaScript class that extends React.Component. Can also be created using React.createClass().
  2. Stateless Functional Component — A JavaScript function that accepts props as parameter and returns React Component. This can be used instead of normal React Component. Also referred to as Pure Component, Dumb Component, available in React>= 0.14. In redux stateless components are often stated as Presentational Component.
  3. Higher Order Component (HOC)— A JavaScript function that accepts React Component as a parameter and returns a new React Component.
  4. Container Component — HOC returned from connect(). It connects your presentational component with redux store.
  5. Redux Store — Immutable JavaScript Object that store the state of your entire application. Note that there is only one store for the entire application.
  6. Middleware — A function that accepts store as parameter and returns dispatch function that accepts action as its parameter. This returned dispatch function will then override the existing store dispatch function.

Maximizing Code Reuse

I will be using react, react-native, react-native-router-flux, redux, react-redux. I will also use 3 most popular redux middlewares for the completeness.

Project Structure

components/Login/actions.js: Implements Action creators for login page.
components/Login/index.js: Imports one or more selectors, actions.js, and Login.js in order to connect them up.
components/Login/Login.js: Presentational component of login page.
reducers/loginReducer.js: Implementation of reducer and selector for login page.
reducers/navReducer.js: Implementation of reducer and selector for navigation.
reducers/rootReducer.js: Imports all other reducers and combine them. Implements higher order selectors for all other selectors.
store/configureStore.js: Imports rootReducer, and all of the middlewares, and use them to create a store.
actionTypes.js: Implements all action types used by reducers and action creators.
App.js: Connects react-native-router-flux’s Router to redux store. Import configureStore.js in-order to create a new store. Implement all of the Scenes declaratively.

Here is all of the code for those files and brief explanation on why I structured it this way.

Entry point of the application. Code is identical in index.android.js
Action creators. Note that you can also take advantage of redux-thunk or redux-promise by returning functions or promises. This is also a place where you can do API calls such as Scene transition.
This is container component of login. I decided to completely take out any mapStateToProps and mapDispatchToProps into other files in order to maximize reusability. Note that this allows me to combine one or more selectors into a single selector. I can also combine one or more mapDispatchToProps if I wanted to as shown below.
This is how you can combine one or more actionCreators into a single mapDispatchToProps.
Presentational component for Login. Note that this.props.title, and this.props.onLogging comes from different selectors. I can also have access to actions from one one or more actionCreators with same concept.
reducer for login. Note that I also have selector here. This is because reducer is where you define how your login state is structured and selectors need to know how it is structured so it makes sense to put them together. also note that my reducer has been exported as default where as my selectors are exported and always starts with “get”
Reducer for my react-native-router-flux navigation. This is useful when you want to know what scene you are currently on as it gets stored in scene. Same idea I have selector in the same file.
This is my root reducer that combines all of my other reducers. Note that because I created a wrapper for my selectors because this allows them to not know about the root structure of the state (ie. state.nav and state.login). If I change my line 9 from login to signin, then all I have to do is change line 16 from state.login to state.signin. This allows me to create a wrapper for all my reducers therefore any other class that needs to import selector will only have to import rootReducer.
This is where I create a new store. In this example I applied 3 most popular redux middlewares. I recommend using them because it makes it allows you to do async dispatch calls without passing reference to dispatch around, and conditional dispatch calls based on state without having to pass state to presentational component and then back to actionCreators.
I put all my ACTION_TYPES in a single file. This allows you to ensure you are not duplicating any actionTypes. However, if you are planning to use a lot more types it may make sense to separate them out into mutiple files and prepend each one with the page name. For example, line 1 can be `export const ON_LOGGIN = ‘LOGIN_onLogin’
Entry point of the application. Connect Router with redux store in line 8. This is where you declare all your scenes.

Here is a link to bitbucket for all of the code above.
https://bitbucket.org/bosung90/rnrf-redux-starterkit/overview

Hopefully with this way of structuring your application you can increase the code re-usability, separation of concerns as much as possible. I know I won’t be making the same mistake again.

--

--