How to Mock Instagram’s Settings UI using Redux Hooks in React Native

avatar
Marshal Murphy
May 09, 2020 - 7 MIN READ

You may be familiar with React Hooks by now, but have you heard of Redux Hooks!?

Soon after React introduced hooks to allow the use of state and effects in function components, Redux followed suit by introducing their own hooks.

Redux hooks allow us to access the Redux store, as well as dispatch actions, from function components!

No longer do we need to implement higher-order components and use connect().

We can now replace mapStateToProps with the useSelector() hook, and mapDispatchToProps with useDispatch().

Let’s mock the Instagram Settings UI to learn how to use Redux Hooks and see them in action!

Feature

Here is the Final Repo if you’d like to skip to the finish line. 🥇

Final product


App Setup with Expo and React Native

To kick this off, let’s get up and running with Expo to launch a basic React Native app on our phone. Here I am going to assume you are familiar with Expo, the Expo mobile app, and the Expo-CLI.

If you are not familiar with Expo, that’s okay! Takes 5 minutes. You can find a quick-start guide in a past article I wrote and published in The Startup titled Up and running with Expo, React Native, & React Navigation 5.0.

Let’s begin in the command line.

Navigate to where you’d like your project to live (ie. Documents, Desktop, etc) and run the following command:

> expo init redux-hooks-rn

You will be prompted to choose a template for building this base app. Select blank.

cmd

When the installation is complete, change directories into the app we just created called redux-hooks-rn.

Let’s just take care of our redux dependencies up front. Use yarn to add both redux and react-redux.

> cd redux-hooks-rn
> yarn add redux react-redux

When this is complete, launch the app!

> yarn start

This will generate a QR code in your terminal and browser. Open up the Expo app on your phone and select Scan QR Code, then scan that QR code 😉.

qr

This will trigger a build and, when complete, our base React Native app will be ready to work with.

blank app


Setting up the Redux Store

Open your app in your favourite text editor and pull up the App.js file.

Very minimal. No navigation. Simply a view with the text you see on the screen.

Our first task is to bring in Redux, create an initial state for the Redux store, and wrap our app in it.

In App.js, let's import our react and react-redux dependencies, destructuring Provider and createStore, respectively. Let's also create a variable to hold our initial state.

Now, the next step in App.js is to create the store, wrap the view in the Provider, and pass in the store.

However, this would return an error as createStore() expects to receive a reducer function.

So, let's jump a head a little bit and create a rootReducer and a settings reducer, as well as an updateSettings() action that will later be used to update our redux store.

Create a new folder called /reducers and an index.js file.

Here we are use combineReducers from redux to return a single function containing all of our reducers.

While in this tutorial we will only be creating a single settings reducer, combineReducers() may be useful for you in the future should you choose to use this demo to build other awesome things.

With our rootReducer in place, let’s now create a settings.js file alongside it.

At the top of this file we import our action for triggering this reducer, which we have not yet written. Before we do that, let’s quickly look at this reducer.

The settings reducer is simple: it takes in an object and merges it into the settings state array, overwriting the old state.

Now for the action.

Create a directory called actions and an index.js file:

This action invokes a simple function called updateSettings, which receives data and passes it along to the settings reducer.

Great! We now have everything we need to implement the redux store!

Back in App.js, let's import our rootReducer, pass it to createStore along with our initialState, and implement the store by wrapping our app in <Provider store={store}/>.

Our App.js should now look like this:

Well that’s great and all, but how do we know it even worked?

Let’s create the UI for our Settings page and use a Redux Hook to retrieve and console log the store.


Settings UI Build and the useSelector Redux Hook

Let’s add our final piece to this setup, the Settings component!

Create one more directory called screens and within it, a Settings.js file for our main component.

First, we are going to move the view out of App.js and into Settings.js.

Now import Settings into App.js and remove the no-longer-used stylesheet.

Nice and clean.

To retrieve the state of the Redux Store, we are going to use the Redux hook useSelector(). This hook allows us to grab the state of the store from within a function component, such as our Settings component.

Update Settings.js to import this hook and use it to console.log() the store.

In our console we can see that our Redux store is indeed setup and our hook worked, with the empty array of our initial state being logged:

> Settings:  Array []

If you change the initial state in App.js to other values, this will be reflected in the console logs too. Woah!

> Settings: Woah!

Mocking Instagram’s Settings UI

Now, for the sake of demonstrating Redux Hooks, I am going to do the heavy lifting here for the UI. There is no need to tediously walk through building out this screen from a UI perspective.

It’s just text and radio buttons.

So, let’s first update the initial state of the redux store so that it can support the UI we are about to assemble.

In App.js, rewrite const initialState = ... like so:

Also in App.js, let’s add a top header bar and some CSS.

Okay, it’s a start, but looking a little wonky at the moment…

blank app

Let’s fix this by updating Settings.js with that heavy lifting I mentioned earlier. Replace Setting.js with the following and we have a UI that looks very similar to Instagram’s Settings UI:

Would you look at that! Like magic, we now have a Settings page!

blank app

I suggest taking a few minutes to read through this new code. The main highlights are:

  • Using the Redux Hook useSelector() to retrieve the settings array from the store.
  • Setting the Status Bar (where your phone displays time, battery, etc) to be dark.
  • Mapping over the settings array to generate the page sections.
  • Passing the props of { option, active, pos, index } to the<Section /> component to generate the rows with the radio buttons.

Naturally, this doesn’t work yet. How about we fix that together, yes? 🤗


Updating the Store with the Redux Hook: useDispatch

The final piece of this project is to be able to update the Redux store using a Redux Hook every time we click an inactive radio button.

To do this, we will use the hook useDispatch().

At the top of Setting.js, import useDispatch alongside useSelector. Also, let's bring in that action we created at the beginning, updateSettings:

Now, within the Section component in Settings.js, we will implement this hook and action:

So, onPress of the empty radios we are triggering an update() function. This function then uses the position (pos) and index to determine where in the settings array we are updating the active value.

This updated settings array of objects is then dispatched to our action updateSettings, which passes it along to our settings reducer.

The settings reducer then simply overwrites the state in the store with the new array of objects being passed to it as settings.

View --> useDispatch --> action --> reducer --> store updates --> UI reflects updated store.

We now have a UI thats works, storing state in Redux using Redux Hooks.

blank app

Now, a number of improvements could be made were this intended for production, such as using the Context API instead of Redux.

However, the goal here is to demonstrate Redux Hooks, and I believe we have done that. 🏆


There we have it! Let’s go over what we learned today:

  • How to quickly deploy a React Native app using Expo to our mobile devices.
  • How to set up Redux in React Native.
  • How to retrieve data from the Redux store using the useSelector() hook.
  • How to dispatch actions to update the Redux store from function components using the useDispatch() hook.

You did well! 💯

Here is the Project Repo again if you’d like to pull it down.

Now go and use this foundation to build something awesome.

Marshal Murphy 2020