Redux: An Intro and Beyond

An Android Developer’s Roadmap to React Native — Part 3

We have already looked at a React component and the state and props associated with a component. You can get an understanding of it here, in the first part of the series.

Lets meet Redux

Redux is a module for React that provides easy, effective and predictable state management. Handling per component state may seem enough for simple applications but as your application grows you will begin to notice the problems with per component state. The most common being that of state sharing between components.
What happens when you are developing an application and the component state stores some information which is required in another component but the original component is removed from the view tree. The component along with its state is lost and there is no way to get that information.
Redux solves this by having an application level state that can be made available to any component of the application. This state does not belong to any particular component but belongs to the application. Thus, Redux in a way, separates this global state from the component without affecting the rendering cycle of the component. Along with a centralized application state, this also serves a few other purposes. The presentation logic is separated from the component (UI). Also, Redux helps in a more organized flow for a state change which is maintainable and predictable.

Building blocks of Redux

Store
This holds the entire application state. Consider it as a global state that can be shared with any component inside your application through Redux.

Action
As the name suggests, it is a call to create a change in the global state, that is, the store. Though, the action itself does not cause any change in the state, it just defines the type of change and any data that may be required for the change. Programmatically, an action is just an object that contains the above mentioned properties.

Action Creator
These are functions that create actions. These are more of a code structure improvement so that a particular action can be created from a single function avoiding duplicate code. An action creator returns an action object.

Reducer
Reducer is the place where the change in store happens. Reducer defines the type of actions it supports and what the changed state of the store will be depending on the action type and data.

Component
The same old React component. There is nothing new to the component, but it plays its part in the Redux life-cycle by calling the required actions to create the desired change in the application state. Very apt, as the state changes based on user interactions and the component is the UI.

Container
The middleman between component and Redux. The container is the place where the component is connected to the Redux store.

Middle-ware
Middle-ware is used to perform some action between the dispatching of action and the reducer changing the state. Once attached to the Redux store, every time an action is dispatched by a component, the middle-ware is called to perform its function before the action reaches the reducer. The middle-ware is independent of the action type and will be called every time an action is called. The most common usage of middle-ware is logging and making API calls.

And a few more..

The Redux store is not available to the connected component directly, but is made available through component props. Redux has a few helper methods to achieve this, as mentioned below:

dispatch :
dispatch is a Redux function to call actions. dispatch accepts an action as the function argument and then does the necessary steps to notify Redux of the action.

connect :
connect is a Redux function that, quite like the name suggests, connects the React component with the store. This function accepts two function as arguments : mapStateToProps and mapDispatchToProps , which are discussed below

mapStateToProps :
Since the store holds the entire application state, a lot of the data in the store may be irrelevant to the component. This function describes what data of the store should be passed to the component as its props.

mapDispatchToProps:
The dispatch function is not made available to the component. Rather, this function maps the actions that the component can dispatch to the component’s props. Each dispatch-able action is passed as a function to the props which the component can call.

A quick swim in the code

Now, that we know the basic Redux terminologies, lets look at basic implementations of the same. This will not be complete code, but relevant snippets from code to get a sense of the Redux life-cycle programmatically and help you setup Redux store in your own application.

  • Reducer:
    Sample reducer that accepts action type ‘SET_EMAIL’ and returns new state according to the action payload.
// LoginReducer.js

export const loginReducer = (state, action) => {
switch (action.type) {
case 'SET_EMAIL':
return Object.assign({}, state, {
email : action.payload.email
})
}
}
  • Combining reducers:
    Your application can have separate reducers for each component that needs access to the store. All these reducers need to be combined to create a store. Here we are just considering a single reducer for simplicity.
    Each reducer maintains a separate state object in the store. Here login is the key for the loginReducer state. We will see the use of this key later when connecting the component to the store.
// index.jsimport { loginReducer } from './../../login/LoginReducer'
import { combineReducers } from 'redux'
const appReducer = combineReducers({
login: loginReducer
});
export default appReducer;
  • Creating store:
    Redux provides a method createStore to create the application store. Here we are also adding a logger middleware to the store using the applyMiddleware function provided by Redux. The combined reducers and the applied middlewares are then passed to createStore function.
// Store.jsimport appReducer from './../reducers';
import { applyMiddleware, compose, createStore} from 'redux'
import { createLogger } from 'redux-logger'
// middleware that logs actions
const loggerMiddleware = createLogger({ predicate: (getState, action) => __DEV__ });
const enhancer = applyMiddleware(
loggerMiddleware
)
export const store = createStore(appReducer,{},enhancer);
  • Action:
    As said before an action is just an object. Here the action has a payload that contains the email ID to be set.
// LoginAction.js{
type : 'SET_EMAIL',
payload : {
email : rohan.a@gmail.com
}
}
  • Action Creator:
    Action creator for the above action.
// LoginAction.jsfunction setEmail(email){
return {
type : SET_EMAIL,
payload : {
email
}
}}
  • Container:
    Sample container that connects Login component to the store. Notice that the email field from the login state is mapped to the component’s props in mapStateToProps. Also the setEmail action is mapped to component’s props in mapDispatchToProps .
// LoginContainer.jsimport {setEmail} from './LoginAction'
import LoginComponent from './LoginComponent'
import { connect } from 'react-redux'
const mapStateToProps = (state) => ({
email : state.login.email
})
const mapDispatchToProps = (dispatch) => ({
setEmail : (email) => dispatch(setEmail(email))
});
export default connect(mapStateToProps, mapDispatchToProps)(LoginComponent);
  • Component:
    Here is a snippet from the login component, where a click on a button calls the mapped dispatch action function from its props.
// LoginComponent.js<TouchableOpacity
onPress={() => {
this.props.setEmail('rohan.a@gmail.com');
}}
style={{ minHeight: 40, justifyContent: "center" }}>
<Text>{'Submit'}</Text>
</TouchableOpacity>

When a user clicks the button, the setEmail action is dispatched by the component, which reaches the middle-ware where the action is logged. The middle-ware then passes the action to the reducer. Reducer sets the email in the login state and returns the new state. This new state is passed to the component as props and if required, the component is re-rendered.

Redux implementation is not very difficult, though it may seem so at first. You just need to get a hang of it by trying it out one or two times. Redux is very beneficial for code structuring, debugging and testing. You should definitely give it a try if you haven’t used it before.

More where this came from

This story is published in Noteworthy, where thousands come every day to learn about the people & ideas shaping the products we love.

Follow our publication to see more stories featured by the Journal team.

Music, Basketball, Life, Learning. Finding my way in life, trying to pursue what I believe in.