React Native integration with Redux and TypeScript (Part 1)

Leandro Ercoli
5 min readAug 8, 2020

--

A non-intimidating guide in two parts to set up React Native projects with state management and static typing integration.

App preview

Concept

We’ll be cloning Instagram’s home UI to understand how to couple Redux and TypeScript with a React Native app. First, we’ll set up the logic for state management and static typing, and then build the UI with React functional components and hooks for internal state management.

Since the focus of this guide is on figuring out how to integrate the different libraries, a basic level of familiarity with each one is assumed.

You can see the full code here.

Initialization

Since Redux is a standalone library that can be paired up with any UI framework, we should also install react-redux to bind it with React and avoid directly interacting with the store from UI code. On a basic Redux store, updates are synchronous: every time an action is dispatched, the state is updated immediately. We can use a middleware like redux-thunk to extend the store’s abilities and handle asynchronous updates (e.g. manage an API call with flags for loading, success and error events).

npm install redux
npm install react-redux
npm install redux-thunk

TypeScript adds static type definitions to better describe the shape of data flowing through the app and validate our code before running it. Follow the official documentation to integrate TypeScript into an existing project.

Given that react-redux doesn’t ship with its own type definitions, we should also install them:

npm install @types/react-redux -D

Structure

There’s probably as many ways to organize files in a project as there are developers in the world, but we should keep in mind some design principles such as separation of concerns and the single-responsibility principle to keep our code well-structured and easy to maintain, especially in a collaborative environment.

What works well for me is structuring the /src folder into:

/assets: static files like images or icons.

/components: presentational React components that receive data through props and return a piece of UI. They are not aware of any Redux logic, but can keep internal state variables concerning the look of the component.

/containers: “smart” React components that connect the Redux store (receiving state updates and dispatching actions) with presentational components. They don’t usually render any visual elements, but rather delegate that responsibility to presentational components.

/extra: files with helper functions, mock data and other utilities that could be reused throughout the application.

/redux: actions, reducers, types and Redux store setup.

/services: API calls organized by modules. I like to use a helper file where I define a get and post function to reuse in all the other API calls, encapsulating all RESTful logic into one file and avoiding code redundancy (DRY principle).

Project structure

Redux & TypeScript

Let’s start by providing a Redux store to our app, wrapping the root node with the <Provider /> component available with react-redux API.

Store provided to root React component

We’ll use Redux API createStore function to create a store from a single reducer and enhance it with redux-thunk middleware to handle async actions.

Store set up

State object

We’ll create a simple state object that keeps data about the posts displayed on the feed and the stories on top, each module managed by a different reducer with its own set of actions. I’ll be doing a walk-through the feed part, but the full code is available here.

{ 
feed: {
posts: [] // array of posts to display on feed
},
stories: {
stories: [], // array of stories to display on top of feed
myStory: [] // array of stories of user to display on top of feed
}
}

Types

By integrating TypeScript into our app we can validate data flow and avoid common mistakes before even running the app. The shape of the state managed by the feed reducer is defined by the interface FeedState, containing a property posts that keeps an array of posts with the shape PostInterface. A post can have different elements, such as a date and time of sharing, the user who shared it (with a shape of UserInterface), an array of images (each with a shape ImgInterface), a caption, and arrays for likes and comments.

Feed state types

Actions

To manage data displayed on feed we’ll expose two actions that can be dispatched from a React container: one to update the feed and one to like a post. By typing our actions and action creators we validate data flow in Redux.

Feed action types

Since we need to call an API on a server to update the feed and like posts, the concerning actions need to be asynchronous. With the help of a middleware like redux-thunk, a dispatched action can return a function instead of an action creator. This allows us to first dispatch a request action that will be captured by a reducer to set a loading flag, then call a backend service (e.g. feedService.updateFeed()), and finally dispatch a success or failure synchronous action on return to update the state in the store accordingly. On the code below, updateFeed is an async action that, when dispatched, triggers a synchronous request action that sets a loading flag, calls a backend service and, when that value is solved, dispatches either a success (updateStoreFeedSuccess) or a failure synchronous action that updates the state.

Feed actions

Reducers

Having already designed the shape of the feed state and the actions available, we can code the reducers that will capture the actions and update the store accordingly. Since we’re splitting the state into two different parts, one to keep the posts on feed and one to keep data about stories, we’ll therefore write two reducing functions. We can type each reducer with the interfaces defined previously (FeedState and FeedActionTypes). Notice the use of the spread operator in the reducer to maintain state immutability.

Feed reducer

Combining reducers

Remember the rootReducer we imported when setting up the store? We’ll use Redux API’s combineReducers function to combine the different reducing functions (feedReducer and storiesReducer), each managing a separate part of the state object, and create a single application-level reducer that will call every child reducer to merge its results in a single state object.

Combining reducers

We’ll be using the exported type RootState later in React UI components to validate the shape of data received from store updates.

Next steps

In Part 2, we’ll be covering the use of Redux and TypeScript on React components: how to dispatch actions and receive state updates, how to type UI components with TypeScript, and how containers and components interact with each other to effectively and reliably share data.

--

--

Leandro Ercoli

Computer Engineer — Full-stack web developer and multi-platform mobile developer