dcsimg

Working with Redux for State Management in Front-End Apps

By Diogo Souza

WEBINAR:
On-Demand

Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame


Redux is a state management library that follows the principles of Flux architecture. I won't go into deep detail here, but what you need to understand are some basic principles of this library.

Global State

Unlike React's standard architecture, the state of components is not stored in the component class itself (except for specific cases). Any and all View information loaded by API, database, or any other endpoint type, is stored in a single global object called State.

This way, each component is manually tied to one or more state variables and, therefore, whenever this information changes, the component is updated to receive the new properties.

Following this concept, think of an application with authentication and to-do list creation, our state would look like this:

{
  auth: {
    username: 'admin',
    name: 'Admin'
  },
  todos: [
    'Do the laundry',
    'Finish the book reading',
    'Start a new series'
  ],
}

Note that I have information from two completely different functionalities stored in the same object.

Actions

Actions are objects that directly indicate an action performed in the software, this Action can be something triggered directly by the user or something triggered by the application itself.

Action always has a unique type property that is used by Redux to distinguish which action is being performed, this concept is called Action Type:

// Example of action

{
  type: 'AUTHENTICATE',
  payload: {
    username: 'admin',
    password: 'admin'
  },
}

It is a good practice to keep all information (except type) within a property called payload. Still thinking about the login action, we could have three actions AUTH_REQUEST, AUTH_SUCCESS and AUTH_ERROR. The first would be triggered directly by the user, whereas the other two would be triggered by the application itself based on the authentication API response.

In order to trigger an Action in our application, we need to wrap this object within the return of a function called Action Creator. This function can then be accessed by any component of the application:

function authenticate(username, password) {
  return {
    type: 'AUTH_REQUEST',
    payload: {
      username,
      password
    },
  };
}

Reducers

Although actions hear actions taken by the user or the application, they don't make any changes to our global state. To change any information in the state we need to use Reducers. Every reducer listens to all actions triggered by the application and it is up to you to decide when it should make any state changes. Following the authentication example, we would have a reducer to handle user authentication information:

function authenticated(state = false, action) {
  switch(action.type) {
    case 'AUTH_SUCCESS':
      return true;
    case 'LOGOUT'
      return false;
    default:
      return state;
  }
}

The first parameter received by the reducer is always the current state and we can initialize the state with a default value (in this case false). The second parameter is our action that contains the type and payload information.

We made a switch to filter the actions that we want to hear with this reducer and, if it doesn't answer any cases, we just return the untouched state.

Each reducer controls a single property in the state, but as this property can be an object or an array, we can store all information regarding each application "module" within that property. For example, in the case of authentication we could store more information:

// State (just for representation)

{
  auth: {
    authenticated: true,
    user: {
      username: 'admin',
      name: 'admin'
    }
    token: 'my_token',
  },

  // ... other props
}

This way, the same reducer can change more than one set of state information because it is encapsulated in an object that represents every authentication module.

Hey, I want to change the store.

Now that store and reducer are on, triggering an action will cause the reducer function to execute. To trigger an action, we use the dispatch method of the store.

store.dispatch(my-action)

But what is an action. anyway? If you answered that it is a simple JavaScript object with a type property, congratulations! So:

store.dispatch({type: '...'})

Conclusion

The best scenario for using Redux is to combine the features that were explored above with the power of the ReactJS or React Native libraries.

With all that you've read, I'd say the best way to really understand Redux is to get your hands dirty. That's why I suggest you start with small projects and increment them with more complex concepts to master this great tool.

About the Author

Diogo Souza works as a Java Developer at PagSeguro and has worked for companies such as Indra Company, Atlantic Institute and Ebix LA. He is also an Android trainer, speaker at events on Java and mobile world.



  • Web Development Newsletter Signup

    Invalid email
    You have successfuly registered to our newsletter.
  •  
  •  
  •  
Thanks for your registration, follow us on our social networks to keep up-to-date