Skip to content

Instantly share code, notes, and snippets.

@amandeepmittal
Created August 4, 2018 09:52
Show Gist options
  • Save amandeepmittal/6f53e31f2fd80d7074afd1da873be309 to your computer and use it in GitHub Desktop.
Save amandeepmittal/6f53e31f2fd80d7074afd1da873be309 to your computer and use it in GitHub Desktop.

Integrating Redux with React Native and Expo

Redux is an important part of React Native ecosystem. If your world revolves around JavaScript, I am sure by now you have heard about Redux. Before reading the rest of the tutorial and going further just try to remember from time to time that you are only learning about redux because it will make things for you easier and not difficult. Now let us learn why do we need the Redux in one of your application.

Need for Redux

Building a React or React Native application in the real world can become complex if there is not a proper way to handle data. If ever, at any point the data is not managed things will go out of your hand. If you are familiar with Reactjs or React Native, you know the default way of handling data is to keep it in a component state and pass it to the children components as props.

State and Props are the only two ways to control data in a component. Props are short for properties and it is a simple rule to follow in React world that we should mutate or change the value of props. In React world the flow of data is unidirectional or one way. That is, the data can always be passed from a parent to a child component. Take a look below at the simple example:

ss1

In the above example, we create two components: Parent and Child and assume in separate files. The Parent component consists of a view where a Child component is rendered. In the child component, the view renders a text message that is incoming from the props. The incoming message is available as the data in the state of the parent component.

This way, the child component can be reused with other parent components such that each parent component can have its own data to render. Do note that, at any point, we are not modifying the value of this.props.

The state is there to mutate data. This is the only reason that the state exists within each component. Whenever we want to change the state we use this.setState() method within a component. This method re-renders the component and all of its child component to reflect the changes. This works both in React and React Native similarly, however, the internals are different.

ss2

Since we can manage state and props so efficiently within a React Native app, where does the necessity of using Redux? Well, the above example is a bare minimum and not at all a real-time scenario. Imagine an application like Instagram or Twitter where you have different screens and each screen may depend on a component or two like the Parent and the reusable Child components from our example. It will be hard to keep track of the state of each component.

Redux is one the most widely adopted and a way of handling data. It enables the state to be shared a global attribute that an entire React Native application can use it and receive it in in the form of props. This is known as creating a store in terms of Redux. Redux simplifies the state by moving it in one place.

Redux uses an underlying React Mechanism called context. We are not going to dwell what is context since it is out of the scope of this article. I just wanted you to know that nothing magical or paranormal is happening behind the scenes.

Just remember the following terms since we are going to see them in action in the tutorial below:

  • Actions
  • Reducers
  • Store

The key to learning Redux is by practice. I am not going to share any more information or visual graphics for the reason that it will only overwhelm things right now. Let us begin by creating a demo application to learn redux.

Building a Pomodoro application

Getting Started

To build this application, I am going to use the latest tool introduced by @Expo team called expo-cli. Install it as a global dependency and then initialize a new React Native project using it.

ss3

To see if everything is working correctly at this initial state, run the following command.

ss4

You will be prompted with the following interface. Take some time to go through it. If you have build applications using Expo XDE or Create-React-Native-App before, you will there is not much change except that now the Expo-CLI makes use of Chrome browser.

ss5

Choose a simulator or device that can run Expo Client as marked in the above image. If you get the below screen that means our React Native project has been initialised without any difficulties.

ss6

With that, create the following files and folders inside the components directory. I will explain later why we are following this directory structure later in this tutorial. For now, our initial setup is complete and we can start building our application.

ss7

Timer Component

First, we will create a dumb Timer component and connect it with App.js. Add the following code to the Timer/index.js.

ss8

Next, modify the App.js file.

ss9

ss10

We will now make a static Timer component to see how things fit in. Start by modifying the StatusBar. Then we are defining two Text elements from react-native library to specify where the actual timer will be displayed and where the buttons for starting and stopping the timer will be displayed. For now, both are text fields.

ss11

ss12

Adding Buttons

In this section, we are going to replace the section that displays Start and Stop Buttons! with actual buttons. We will be using TouchableOpactiy to make this work. A TouchableOpacity component act as a wrapper for making views respond properly to touches. The opacity of the wrapped view or the button in our case gets decreased whenever a user touches it.

We are creating a reusable component since we need two buttons: Start and Stop.

ss13

This is a stateless component, see no class because we only need it to represent the Button in the UI of our app. We are also importing FontAwesome icons from @expo/vector-icons which is a fork of react-native-vector-icons and comes directly with the expo SDK. No need to install it as a separate dependency. To display an icon, we to define its size.

Lastly, in the above stateless component, we are defining propTypes. I will be discussing how and why we should use PropTypes in a React Native application in another article.

In a mobile app, events are triggered due to touches and to handle those events we are going to use onPress. We will have only two events here, Start and Stop. Both the buttons in our app are going to make use of onPressOut which differs from onPress . The onPressOut is called whenever the touch is released by the user, that is, the user has released pressing the button. It is called before onPress and is more accurate in a situation like ours where we need to start or stop the timer as soon as the user is done by pressing the button.

We will now require this Button component in our Timer component.

ss14

ss15

Integrating Redux

So far, our Timer application does not do anything other than displaying a bare minimum UI. To make it work, we start by adding needed redux dependencies.

ss16

Now, let us start integrating Redux in our app.

Actions

In Redux, the state of the whole application is represented by one JavaScript object. Think of this object as read-only since we cannot make changes to this state (which is represented in the form of a tree) directly. We nees actions to do so.

Actions are like events in Redux. They can be triggered in the form of mouse clicks, key presses, timers or network requests. The nature of each event mentioned is mutable. An action is a JavaScript object. To define an action, there is one requirement that is each action much have its own type property. We define these types in a file called types.js:

ss17

Our application needs only three actions so far. The type of any action is a string value and are defined as constants.

In the file actions.js we will require these types to define action creators. Actions Creators are functions that create actions.

ss18

Reducers

The receiver of the action is known as a reducer. Whenever an action is triggered, the state of the application changes. The handling of the application's state is done by the reducers.

Reducer is a pure function that calculates the next state based on the initial or previous state. It always produces the same output if the state is unchanged. It takes two inputs: state and action must return the default state.

ss19

In our initial state, we define three attributes: isPlaying, elapsedTime and timerDuration which currently has a default value of 6 (seconds) for testing purposes but the actual value we are going to change later is 25 (or 1500 seconds). Then, there are three helper functions: applyStartTimer that will start the timer, applyRestartTimer that will stop the timer function set everything to default and lastly, applyAddSecond function which checks if time passed by is less than the total timer's duration, add one more second to increase its value. If the not, return the default state and stop the timer function from running.

After that, we define our reducer function and export the same function. Observe how the reducer function is organized. This is a pattern followed by most community memebers I have seen on the internet.

Creating Store

With the help of the reducer and the initial state, we can create the store object.

ss20

A store is an object that brings and actions and reducers together. It provides and holds state at the application level instead of individual components. Redux is not an opinionated library in terms which framework or library should use it or not, to bind a React or React Native application with Redux is done react-redux module. This is done by using a high ordered component Provider. It basically, passes the store down to the rest of the application.

We need to bind action creators with our Timer function in order to make it fully working and respond to the touchable events or start or restart the timer. We will be doing this in Timer/index.js function. First, we import our the required dependencies to bind action creators.

ss21

bindActionCreators maps action functions to an object using the names of the action functions. These functions automatically dispatch the action to the store when the function is called. To change the data we need to dispatch an action. For this to enable, we need to things: mapStateToProps, mapDispatchToProps and connect both of them with our component. This is the boilerplate code that you will be re-writing.

We define these two functions and modify our export default statement after we define the styles for our React Native views.

ss22

mapStateToProps is an object that lives in the store whose keys are passed down to the component as props. The below is the complete code for the Timer component.

Completing The App

ss23

I have created a custom function called formatTime to display time in the correct format but you can make you use of any timer library. Next, to increment the value of time, I am using React lifecycle method componentWillReceiveProps. I know it is going to deprecated soon, but for now it works. See our mini-app in action below:

ss24

For brevity and demo purpose I am using only seconds to display the timer. You can increase the value of the timer by editing the value of constant TIMER_DURATION in reducers.js.

We have reached the end of the article. Hopefully, you have had fun reading it as much as I enjoyed writing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment