How to use Redux in React?

Eric Kim
7 min readJun 13, 2016

--

Redux has taken Javascript community by storm and for a good reason; simple implementation and predictable application state.

What is Redux in React?

Redux is a design pattern, and redux library is a simple library that helps you follow this design pattern. React-redux, for instance, is simply an extension to redux library to help people implement Redux in React.

Traditional React(-Native) Applications

Traditionally in React(-Native), you have a tree structure of components where the state is stored throughout the application within each component.

From http://code.tutsplus.com/tutorials/intro-to-the-react-framework--net-35660

Downside of Traditional React Applications

Storing state throughout the application requires minimum boilerplate to get started. In React, data should only flow one direction down in the tree hierarchy. Therefore the problem occurs when component A contains a state that its sibling component B also requires. You can avoid this by structuring your application properly at a design phase, but this does not happen in real-life scenario as requirements often change throughout the development cycle. Ideally you would then restructure your application by moving the shared state from children to the lowest common parent. However, this re-structuring can be very time consuming. Another way to fix this is by subscribing to other components for any changes in the state. However, this can make application extremely complex as each component can potentially listen to every other component for its changes in the state.

Second, the problem gets even worse if a component fetches data from another sibling component whenever it requires the data(i.e. constructor or componentWillMount). This would first require a sibling component to have reference to another component, and the source of the truth is no longer clear as you have two sources of the same information.

Lastly, the state of the application is not very predictable. Imagine you have 10 check boxes throughout your application. This means your app can be in one of 2¹⁰ possible states at any given time. If your application is in a bad state (for example, first and third checkbox cannot be both checked, but it is), it can be hard to debug and reproduce. Using redux will not reduce the total number of states which your application can be in, but it will make it very predictable and reproducible as there is only one path to change the state of the application. This path to change the state then can be logged, traced, reproduced, and even reversed.

How Redux works

The most important concept of Redux is that it has one global store that stores all the state of the application. Any component can subscribe to the store in order to get notified of any changes in the state. React-redux makes this even simpler by allowing you to use connect function inside any component wrapped within Provider component to subscribe to the store without requiring a reference to the store object. Once connected, state of the application will be available inside mapStateToProps function.

const mapStateToProps = (state) => ({title: state.title})export default connect(mapStateToProps)(BlogComponent)

React Components in Redux

There are two types of React components:
1) container components and
2) presentational components.

Container components acts as a wrapper for presentational components which facilitates the data from the store to dispatching an action to the store. Presentational components are stateless components that only deals with rendering the data with correct style. Presentational components does not have reference to any container component as all the necessary data and event functions are passed down from the container component.

Reducer in Redux

The initial state of the application comes from reducer(s).

Reducer is a function that accepts previous state and action as parameter, and returns a new state of the application based on the action.

Whenever you want to change the state of the application, you must dispatch an action.

Dispatch is simply a function available within the store object.
Action is simply a JavaScript object containing a field called type and any other optional field of your choice.

This action then goes through reducer(s) where you can check for type and use previous state to create and return a new state of the application.

const action = {
type: 'newBlogPost', title: 'Using Redux in React Native'
}
dispatch(action)

By using React-redux’s connect function, you will have access to dispatch function within mapDispatchToProps without a reference to the store object.

const mapStateToProps = (state) => {
return {title: state.title}
}
const mapDispatchToProps = (dispatch) => {
return {
writeBlog(title){
const action = { type: 'newBlogPost', title: title }
dispatch(action)
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(BlogComponent)

Now that you have a bit more clear picture of the redux, here is how the data flows through the application.

  1. Global store calls mapStateToProps function inside container component with its global state.
  2. Container component passes down the filtered global state into its connected presentational component as props. This happens inside mapStateToProps function. Container component also passes down event functions as props that presentational components can call (eg. onClick) as props.
  3. Presentational component uses the data passed in as props to render and style the view. Upon some event (ie. onClick), presentational component calls an event function passed down directly from container component as props. (ie. `this.props.writeBlog(data)` )
  4. The event function will call dispatch function with an action.
  5. Action gets passed into reducer where a new state is returned based on previous state. This will update/replace the global state.
  6. Whenever global state changes, it calls mapStateToProps in all of the affected container components (Step 1).

However, this data life cycle of redux is missing one crucial step necessary in many applications, external API call such as fetch.

So the question is where in the life cycle of the application should you make this call?

Two places that you should never do is within mapStateToProps and inside reducer. The reason is pretty simple. You do not have access to dispatch function and even if you do, you would likely call the same API multiple times and even worse, create an infinite loop.

Another way to do it is inside presentational components. This one will work as intended as downside is not as subtle as the first two. However, this is still not the correct answer. Presentational components should be dumb and only worry about styling of the UI based on data being passed in as props. This makes presentational components reusable as any logic to API call / dispatch an action is not part of it.

More than one presentational components can share same container components and vice versa.

The correct answer is inside mapDispatchToProps function. This is where you have access to the dispatch function, so upon callback from API you can dispatch an action to change the state of the application.

How to scale redux application

Because redux has only one global state that is available to all container components, it makes it easy to scale horizontally. Every time you need to add a new page, you can simply create a new container and presentational components and connect to the store without requiring reference to multiple other existing components.

Note that trying to avoid duplicated code still applies here, so try to reuse as much presentational and container components as possible.

If you have made sure presentational components are stateless and only deals with rendering the data passed in from props (ie. no dispatch or external API calls), then reusing them becomes really easy. It is like any other React components, such that you simply pass different data from container component to render different UIs.

const mapStateToProps = (state) => {
return {title: state.title}
}
const FirstContainer = connect(mapStateToProps)(BlogComponent)
const mapStateToPropsTwo = (state) => {
return {title: state.subTitle}
}
const SecondContainer = connect(mapStateToPropsTwo)(BlogComponent)

Reusing Container components is very similar. This is useful when same set of data has to be rendered differently. Basically they are using the same mapStateToProps function.
Reusing mapDispatchToProps is same, however, in certain situations where you want to delay dispatch, or conditionally dispatch based on current store state, it can be a bit of a challenge. In this case, you can use redux middlewares such as redux-thunk in order to maximize code reuse and not pass dispatch outside of container component.

One important to note is that redux store is immutable. This means storing large amount of data can slow down the application. This is why you must store minimum amount of data in redux store to render the state of the application, and resolve to AsyncStorage, Realm, or JavaScript object when it comes to storing large amount of data. For instance, in order to render a paragraph, instead of storing entire paragraph in redux store, you can store that paragraph in AsyncStorage, Realm, or plain JavaScript object and only put the id of the paragraph in redux store.

const mapStateToProps = (state) => {
return {
paragraph: AsyncStorage.get(state.paragraphId)
}
}
export default connect(mapStateToProps)(BlogComponent)

Another benefit of this doing is that you can localize your string very easily.

That’s all I wanted to cover in my first medium post.

Thank you

Originally published at ghost.mybluemix.net on June 13, 2016.

--

--