📄 Table of contents

◉ What is Redux?

However, Redux is most often used together with React.

Redux is very lightweight measuring only 2KB.

In React, data flows from parent component to child component in the form of props. In react mostly everything is component, so if there are too many number of components, here comes the role of redux as it manages the states of all components.

The Problem With Traditional MVC Architecture

However the disadvantage is that you’re loosing control of your data flow. In general the data flow is bi-directional. The user input in one component can affect other components and vice versa. Controlling the flow of data and making sure that all user interface components update accordingly is an error-prone task.

How State Management Solves The Problem

Building Blocks Of Redux

The key points of interest while working with redux are as below:

[1]. Action

Actions are JavaScript objects as you can see in the following example:

{
type: LOGIN_USER,
payload: {username: ‘sebastian’, password: ‘123456’}
}

Action objects are created by using functions. These functions are called action creators:

function authUser(data) {
return {
type: LOGIN_USER,
payload: data
}
}

Here you can see that the only purpose of an action creator function is to return the action object as described.

[2]. Dispatcher ->collects the action that is actively triggered and passes it to reducer.

Calling actions in the application is easy by using the dispatch method:

dispatch(authUser(data));

[2.5] middleware -> extend the functionality of our redux application.

[3]. Reducers

Reducers are pure JavaScript functions that take the current application state and an action object and return a new application state:

function myReducer (state , action)  {
switch (action.type) {
case 'LOGIN_USER':
return Object.assign({}, state, {
auth: action.payload
})
default:
return state
}
}

The important thing to notice here is that the state is not changed directly. Instead a new state object (based on the old state) is created and the update is done to the new state.

[4]. Store -> which holds our state (single source of data).

The store is the central objects that holds the state of the application. The store is created by using the createStore method from the Redux library:

import { createStore } from ‘redux’;
let store = createStore(myReducer);

You need to pass in the reducer function as a parameter. Now you’re ready to disptach a action to the store which is handled by the reducer:

let authData = {username: ‘sebastian’, password: ‘123456’};
store.dispatch(authUser(authData));

for more…watch this video tutorial https://egghead.io/courses/getting-started-with-redux to have an understanding of Redux.

Simplest working example of react along with redux:

◉ Basic Redux Setup

Minimal Redux BareBone setup
Counter Container Component

◉ Middleware in React/Redux

Redux also provides us with a middleware, this middleware are functions that allow us extend the functionality of our redux application.

The middleware sits in between the dispatch and reducers, which means we can alter our dispatched actions before they get to the reducers or execute some code during the dispatch.

The three most widely used and stable Redux Ajax middleware are:

  1. Redux Promise Middleware
  2. Redux Thunk Middleware
  3. Redux Saga Middleware

An example of a redux middleware is redux-thunk which allows you to write action creators that return a function instead of the typical action (object).

This is the standard way of doing Ajax with Redux.

When using Redux Thunk, your action creators returns a function that takes one argument dispatch:

function getUserName(userId) {
return dispatch => {
return fetch(`/api/personalDetails/${userId}`)
.then(response => response.json())
.then(json => dispatch({ type: "SET_USERNAME", userName: json.userName })
}
}

dispatch is a function that dispatches an action. The action creator can call dispatch inside .then to execute it Asynchronously. The action creator can call dispatch as many time as it wants.

When to use

  • You require full control of the format of your actions

◉ Creating custom Middleware in React/Redux.

Redux library, and it’s modules.

Writing a middleware is very easy, and below is a basic code to create your middleware.

const customMiddleware = store => next => action => {
...
}

Above means our middleware receives a store, then returns a function that receives a next function and returns another function that receives an action.

As you can see, the middleware is a curried function.

What is a curried function? A curried function is a function that returns another function.

Example:

const foo = a => b => a + b;
foo(1)(2); //=> 3
OR in ES5function foo(a) {
return function(b) {
return a + b;
}
}

The Store: That’s our redux store.

The Next: We call this function when our middleware is done with the task assigned to do. This sends our actions to our reducer or another middleware.

The Action: Thats our action currently being dispatched.

Now let’s write some code:

I have forked the react-redux repo to quickly help us get started with writing code, and i would be working with the counter example.

To apply a middleware in redux, we would need to require the applyMiddleware function from the redux library.

import {createStore, applyMiddleware} from "redux";

In order to check that our middleware is hooked up correctly, we can start by adding a log to display a message when an action is dispatched.

Now if we go ahead to trigger an action by clicking a button, we would see the logged message in our console.

On dispatch, middlewares are triggered.

In our middleware we have access to store.getState() to get the current state and store.dispatch() to dispatch a new action if we want to.

Next we can add another middleware to trigger an event when we click the increment button.

Easy as pie! isn’t it.

An exercise you can try out: Display a loader icon when your actions make request to your backend to process data and clear the loader icon when data gets to your reducers.

References: https://medium.com/netscape/creating-custom-middleware-in-react-redux-961570459ecb

Redux-Thunk vs. Redux-Saga

While building my first basic CRUD (create, read, update and delete) application, I was stumped as to how to integrate my axios data request into a Redux action creator. How do I bake in this layer of asynchronous code and feed the data to my Redux store? After researching, I found Redux-Thunk middleware to be a possible solution. This super helpful middleware allowed me to write an intermediary function, a thunk, that would make the ajax request and then call the action creator using the data received in the response of the object. As I continued to read other articles, I found that this was only one solution of several middleware options available.

But why a middleware is required ?

Hence, to support Asynchronous(-ity), middleware(s) comes to the rescue!

Middleware allows for asynchronous data flow, interprets anything that you dispatch and finally returns a plain object allowing the synchronous Redux data flow to resume. Redux middleware can thus solve for many critical asynchronous needs (e.g., axios requests).

Redux-thunk

A thunk is a function that acts as a wrapper in that it wraps an expression to delay its evaluation.

For example, in the below code, the foo function acts as a thunk as it delays the calculation of the mathematical expression, 1 + 2.

According to Eric Raymond, the inventors of the thunk coined the term “after they realized (in the wee hours after hours of discussion) that the type of an argument in Algol-60 could be figured out in advance with a little compile-time thought […] In other words, it had ‘already been thought of’; thus it was christened a thunk, which is ‘the past tense of “think” at two in the morning”.

In the context of Redux, Redux-Thunk middleware allows you to write action creators that return a function instead of the typical action object. The thunk can then be used to delay the dispatch of an action until the fulfillment of an asynchronous line of code (e.g., an axios request to receive data).

Below is an outline of the step-by-step process of Redux-Thunk:

1.If it is a regular action object, Redux-Thunk does not do anything and the action object is processed by the store’s reducer.

2. If the action is a function, Redux-Thunk invokes it and passes it the store’s dispatch and getState methods and any extra arguments (e.g., axios)

3. After the function runs, the thunk then dispatches the action, which will then update the state accordingly.

Thus, in summary there are two parts to Redux-Thunk:

  1. A thunk creator, which is an action creator that returns a thunk (a.k.a. asynchronous action creators)
  2. The thunk itself, which is the function that is returned from the thunk creator and accepts dispatch and setState as arguments

Below is a graph of the npm downloads, over the past six months, for these other middleware options.

The other most commonly used middleware is Redux-Saga.

Redux-Saga

How redux-saga works ?

Now coming to the project, we need to create to create actions, reducers and store for both redux-thunk and redux-saga. So in terms of configuration, pretty much entire code is same. Just the action part in redux-saga becomes really simple when generators kick in making redundant code of dispatches obsolete.

The idea is that a saga is similar to a separate thread in your application that’s solely responsible for side effects.

However, unlike Redux-Thunk, which utilizes callback functions, a Redux-Saga thread can be started, paused and cancelled from the main application with normal Redux actions. Like Redux-Thunk, Redux-Saga has access to the full Redux application state and it can dispatch Redux actions as well.

To do this, Redux-Saga utilizes a new ES6 feature called generators. Generators are functions which can be exited and later re-entered.

Simply, calling a generator function, marked by the asterisk to the right of the function keyword, will not cause the body of the function to execute immediately. Instead an iterator object is returned (e.g., gen in the above example). When the iterator’s next method is invoked, the generator function’s body is executed up until the first yield (e.g., line 2 above). The iterator’s next method returns an object with a value property containing the yielded value and a done boolean property, which indicates whether the generator has yielded its last value.

But let’s take a step back. What is yield?

Line 2 above is called a ‘yield expression’ because when you restart the generator, you will send back in the value and it will be used as the newly evaluated value. In essence, the yield keyword makes a request for a value.

Unlike typical JavaScript functions, generator functions run through to completion. Generator functions can be ‘cooperative’, which is a function that chooses when it will allow an interruption, so that it can cooperate with other code. You can use the yield keyword to pause the function from inside of itself. Note that nothing can pause the generator from the outside. However, once paused the generator cannot restart itself. Only an external control can be used to restart the generator function.

So who wins? Redux-Thunk or Redux-Saga?

Redux thunk version
Redux-saga version

The benefit to Redux-Saga in comparison to Redux-Thunk is that

[1]. you can avoid callback hell meaning that you can avoid passing in functions and calling them inside.

[2]. Additionally, you can more easily test your asynchronous data flow. The call and put methods return JavaScript objects. Thus, you can simply test each value yielded by your saga function with an equality comparison. On the other hand, Redux-Thunk returns promises, which are more difficult to test. Testing thunks often requires complex mocking of the fetch api, axios requests, or other functions. With Redux-Saga, you do not need to mock functions wrapped with effects. This makes tests clean, readable and easier to write.

[3]. Redux-Thunk, however is great for small use cases and for beginners. The thunks’ logic is all contained inside of the function. Additionally, you do not need to learn a new function type, generators, and the keywords and methods associated with this function type. In conclusion, there are tradeoffs for each middleware and depending on your project, you can decide which middleware is most fitting for your code.

Now if you see we are able to pass the promises to redux-saga middleware and it handles it automatically. This is something I was looking forward to because it does not involved dispatch and redundancy of code goes down drastically.

source: https://tudip.com/blog-post/why-react-saga-is-better-then-thunk/

Middleware

A thunk is a function that acts as a wrapper in which it wraps an expression to delay its evaluation. Thunk allows to write an action creators that return a function instead of the typical action object.

Where as redux-saga is a library that mainly focuses on easy handling of application side effects and more efficient for execution.

Redux-thunk

Here is the basic structure of Redux-thunk:-

export const thunkName = parameters => (dispatch, getState) => {
// You can write your application logic here
};

Example:

import axios from "axios";
import GET_LIST_API_URL from "../config";
const fetchList = () => {
return (dispatch) => {
axios.get(GET_LIST_API_URL)
.then((responseData) => {
dispatch(getList(responseData.list));
})
.catch((error) => {
console.log(error.message);
});
};
};
const getList = (payload) => {
return {
type: "GET_LIST",
payload
};
}
export {fetchList}

Redux-saga

Example:

import axios from "axios";
import GET_LIST_API_URL from "../config";
import {call, put} from "redux-saga/effects";
const fetchList = () => {
return axios.get(GET_LIST_API_URL);
}
function* fetchList () {
try {
const responseData = yield call(getCharacters);
yield put({
type: "GET_LIST",
payload: responseData.list});
}
catch (error) {
console.log(error.message);
}
}
export {fetchList};

Conclusion

◉ List of Redux Alternatives

[2]. Relay & GraphQL

However, Redux is known to be the most popular library for managing state across your React application.

Reducer Example

◉ Immutability in React

In other words, if React can’t figure out that the state of a component has changed, then it will not not know to update the Virtual DOM.

Immutability, when enforced, makes it possible to keep track of those changes. This allows React to compare the old state of an object with it’s new state and re-render the component based on that difference.

This is why directly updating state in React is often discouraged:

this.state.username = "jamesdoe";   X(not recommended )

React will not be sure that the state has changed and is unable to re-render the component.

◉ Updating (Mutating) state

Example 2:

let user = { name: "James Doe", location: "Lagos" }
let newUser = user;
user.location = "Abia";
console.log(newUser.location) // "Abia" (NOT what we expected)

Experience with Front-end Technologies and MERN / MEAN Stack. Working on all Major UI Frameworks like React, Angular.