React.js & Redux Crash Course for Beginners - Full Tutorial

React.js & Redux Crash Course for Beginners - Full Tutorial

In this React.js & Redux crash course you will learn what React.js is and the fundamentals such as components, state, props, JSX, events, etc. We will talk about what Redux is and build a React app from scratch and add all of the boilerplate for Redux and work with the store/state, actions, reducers and all of the other fundamentals of the Redux state manager.

React.js Crash Course for Beginners - Full Tutorial

In this crash course you will learn what React JS is and the fundamentals such as components, state, props, JSX, events, etc.

Redux Crash Course for Beginners - Full Tutorial

In this video we will talk about what Redux is and build a React app from scratch and add all of the boilerplate for Redux and work with the store/state, actions, reducers and all of the other fundamentals of the Redux state manager. The actual Redux implementation starts around 22:00.

Why React Hooks + Context API a better choice than React + Redux

Why React Hooks + Context API a better choice than React + Redux

In this React tutorial, I will introduce the React Context API for state management, and show you what makes React Hooks plus the Context API a better solution than React plus Redux

Redux introduces a lot of complexity to our codebase with the excessive amount of code it requires. At best, this makes it an imperfect solution for state management in React applications. And yet, far too many React developers default to Redux for state management without considering other alternatives.

In this article, I will introduce the React Context API for state management, and show you what makes React Hooks plus the Context API a better solution than Redux.

Why we need a state management tool

In typical React, the way to handle data between disconnected components is through prop drilling. Since there is no global state that components can access if, for instance, you want to pass data from a top-level component to a fifth-level component, you’ll have to pass the data as a prop on each level of the tree until you get to your desired component.

This results in writing a ton of extra code, and giving components properties that they will never use also affects their architectural design. In order to solve this problem, we needed a way to provide a global state that all components, no matter how deeply nested they are, could access.

By solving this, Redux, an open-source JavaScript library for managing application state, became the go-to solution for React developers.

How Redux works

The Redux documentation describes it as a predictable state container for JavaScript applications that helps us to write applications that behave consistently, run in different environments, and are easy to test.

One disadvantage of prop drilling is the need for writing a considerable amount of extra code in order to access data from a top-level component. With Redux, this disadvantage is felt even more as a lot of complexity comes with all its extra code required for setting up a global state for our application. Redux requires three main building parts to function: actions, reducers, and store.

Actions

These are objects that are used to send data to the Redux store. They typically have two properties: a type property for describing what the action does and a payload property that contains the information that should be changed in the app state.

// action.js
const reduxAction = payload => {
  return {
    type: 'action description',
    payload
  }
};

export default reduxAction;

The type is usually in all caps, with its words separated by underscores. For example, SIGNUP_USER or DELETE_USER_DATA.

Reducers

These are pure functions that implement the action behavior. They take the current application state, perform an action, and then return a new state:

const reducer = (state, action) => {
  const { type, payload } = action;
  switch(type){
    case "action type":
      return {
        ["action description"]: payload
      };
    default:
      return state;
  }
};

export default reducer;

Store

The store is where the application’s state is housed. There is only one store in any Redux application:

import { createStore } from 'redux'

const store = createStore(componentName);

Since our application can only have one Redux store, in order to create a single root reducer for all our components, we’ll need the [combineReducers](https://redux.js.org/api/combinereducers) method from Redux.

With this long process and considerable amount of code required to set up Redux, imagine what our codebase will look like when we have multiple components to work with. Even though Redux solves our state management problem, it is really time-consuming to use, has a difficult learning curve, and introduces a whole new layer of complexity to our application.

Fortunately, the React Context API solves this problem. When combined with React Hooks, we have a state management solution that is less time-consuming to set up, has an easy learning curve, and requires minimal code.

The React Context API

The new Context API came with React 16.3. Here’s how Context is explained in the React documentation:

Context provides a way to pass data through the component tree without having to pass props down manually at every level.

The React context API is React’s way of managing state in multiple components that are not directly connected.

To create a context, we’ll use the createContext method from React, which accepts a parameter for its default value:

import React from 'react';

const newContext = React.createContext({ color: 'black' });

The createContext method returns an object with a Provider and a Consumer component:

const { Provider, Consumer } = newContext;

The Provider component is what makes the state available to all child components, no matter how deeply nested they are within the component hierarchy. The Provider component receives a value prop. This is where we’ll pass our current value:

<Provider value={color: 'blue'}>
  {children}
</Provider>

The Consumer, as its name implies, consumes the data from the Provider without any need for prop drilling:

<Consumer>
  {value => <span>{value}</span>}}
</Consumer>

Without Hooks, the Context API might not seem like much when compared to Redux, but combined with the useReducer Hook, we have a solution that finally solves the state management problem.

What are Hooks in React?

Hooks are a type of function that enables the execution of custom code in a base code. In React, Hooks are special functions that allow us to “hook into” its core features.

React Hooks provide an alternative to writing class-based components by allowing us to easily handle state management from functional components.

The useContext Hook

If you noticed, when explaining the React Context API, we needed to wrap our content in a Consumer component and then pass a function as a child just so we could access (or consume) our state. This introduces unnecessary component nesting and increases the complexity of our code.

The useContext Hook makes things a lot nicer and straightforward. In order to access our state using it, all we need to do is call it with our created context as its argument:

const newContext = React.createContext({ color: 'black' });

const value = useContext(newContext);

console.log(value); // this will return { color: 'black' }

Now, instead of wrapping our content in a Consumer component, we can simply access our state through the value variable.

The useReducer Hook

The useReducer Hook came with React 16.7.0. Just like the reduce() method in JavaScript, the useReducer Hook receives two values as its argument — in this case, the current state and an action — and then returns a new state:

const [state, dispatch] = useReducer((state, action) => {
  const { type } = action;
  switch(action) {
    case 'action description':
      const newState = // do something with the action
      return newState;
    default:
      throw new Error()
  }
}, []);

In the above block, we’ve defined our state and a corresponding method, dispatch, handling it. When we call the dispatch method, the useReducer() Hook will perform an action based on the type that our method receives in its action argument:

...
return (
  <button onClick={() =>
    dispatch({ type: 'action type'})}>
  </button>
)
The useReducer Hook plus the Context API

Setting up our store

Now that we know how the Context API and the useReducer Hook work individually, let’s see what happens when we combine them in order to get the ideal global state management solution for our application. We’ll create our global state in a store.js file:

// store.js
import React, {createContext, useReducer} from 'react';

const initialState = {};
const store = createContext(initialState);
const { Provider } = store;

const StateProvider = ( { children } ) => {
  const [state, dispatch] = useReducer((state, action) => {
    switch(action.type) {
      case 'action description':
        const newState = // do something with the action
        return newState;
      default:
        throw new Error();
    };
  }, initialState);

  return <Provider value={{ state, dispatch }}>{children}</Provider>;
};

export { store, StateProvider }

In our store.js file, we used the createContext() method from React that we explained earlier to create a new context. Remember that the createContext() method returns an object with a Provider and Consumer component. This time, we’ll be using only the Provider component and then the useContext Hook when we need to access our state.

Notice how we used the useReducer Hook in our StateProvider. When we need to manipulate our state, we’ll call the dispatch method and pass in an object with the desired type as its argument.

In our StateProvider, we returned our Provider component with a value prop of state and dispatch from the useReducer Hook.

Accessing our state globally

In order to access our state globally, we’ll need to wrap our root <App/> component in our StoreProvider before rendering it in our ReactDOM.render() function:

// root index.js file
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { StateProvider } from './store.js';

const app = (
  <StateProvider>
    <App />
  </StateProvider>
);

ReactDOM.render(app, document.getElementById('root'));

Now, our store context can be accessed from any component in the component tree. To do this, we’ll import the useContext Hook from react and the store from our ./store.js file:

// exampleComponent.js
import React, { useContext } from 'react';
import { store } from './store.js';

const ExampleComponent = () => {
  const globalState = useContext(store);
  console.log(globalState); // this will return { color: red }
};

Adding and removing data from our state

We’ve seen how we can access our global state. In order to add and remove data from our state, we’ll need the dispatch method from our store context. We only need to call the dispatch method and pass in an object with type (the action description as defined in our StateProvider component) as its parameter:

// exampleComponent.js
import React, { useContext } from 'react';
import { store } from './store.js';

const ExampleComponent = () => {
  const globalState = useContext(store);
  const { dispatch } = globalState;

  dispatch({ type: 'action description' })
};
Conclusion

To a good extent, Redux works for state management in React applications and has a few advantages, but its verbosity makes it really difficult to pick up, and the ton of extra code needed to get it working in our application introduces a lot of unnecessary complexity.

On the other hand, with the useContext API and React Hooks, there is no need to install external libraries or add a bunch of files and folders in order to get our app working. This makes it a much simpler, more straightforward way to handle global state management in React applications.

React Redux Tutorial – Efficient Management of States in React

React Redux Tutorial – Efficient Management of States in React

React is one of the most popular JavaScript libraries which is used for front-end development. It has made our application development easier and faster by providing the component based approach...

React is one of the most popular JavaScript libraries which is used for front-end development. It has made our application development easier and faster by providing the component based approach...

React Redux Tutorial

As you might know, it’s not the complete framework but just the view part of the MVC (Model-View-Controller) framework. So, how do you keep track of the data and handle the events in the applications developed using React? Well, this is where Redux comes as a savior and handles the data flow of the application from the backend.

Through this blog on React Redux tutorial, I will explain everything you need to know on how to integrate Redux with React applications. Below are the topics I will be discussing under React Redux tutorial:

  • Why Redux With React?
  • What Is Redux?
  • Advantages Of Redux
  • Components Of Redux
  • React with Redux

Why Redux With React? – React Redux Tutorial

As I have already mentioned that React follows the component based approach, where the data flows through the components. In-fact, the data in React always flows from parent to child components which makes it unidirectional. This surely keeps our data organized and helps us in controlling the application better. Because of this, the application’s state is contained in specific stores and as a result, the rest of the components remain loosely coupled. This makes our application more flexible leading to increased efficiency. That’s why the communication from a parent component to a child component is convenient.

But what happens when we try to communicate from a non-parent component?

A child component can never pass data back up to the parent component. React does not provide any way for direct component-to-component communication. Even though React has features to support this approach, it is considered to be a poor practice. It is prone to errors and leads to spaghetti code. So, how can two non-parent components pass data to each other?

This is where the React fails to provide a solution and Redux comes into the picture.

Redux provides a “store” as a solution to this problem. A store is a place where you can store all your application state together. Now the components can “dispatch” state changes to the store and not directly to the other components. Then the components that need the updates about the state changes can “subscribe” to the store.

Thus, with Redux, it becomes clear where the components get their state from as well as where should they send their states to. Now the component initiating the change does not have to worry about the list of components needing the state change and can simply dispatch the change to the store. This is how Redux makes the data flow easier.

What Is Redux? – React Redux Tutorial

Just like React, Redux is also a library which is used widely for front-end development. It is basically a tool for managing both data-state and UI-state in JavaScript applications. Redux separates the application data and business logic into its own container in order to let React manage just the view. Rather than a traditional library or a framework, it’s an application data-flow architecture. It is most compatible with Single Page Applications (SPAs) where the management of the states over time can get complex.

Redux was created by Dan Abramov and Andrew Clark around June 2015. It was inspired by Facebook’s Flux and influenced by functional programming language Elm. Redux got popular very quickly because of its simplicity, small size (only 2 KB) and great documentation.

Principles Of Redux

Redux follows three fundamental principles:

***1.Single source of truth: ***The state of the entire application is stored in an object/ state tree within a single store. The single state tree makes it easier to keep track of the changes over time and debug or inspect the application. For a faster development cycle, it helps to persist the application’s state in development.

***2.State is read-only: ***The only way to change the state is to trigger an action. An action is a plain JS object describing the change. Just like the state is the minimal representation of data, the action is the minimal representation of the change to that data. An action must have a type property (conventionally a String constant). All the changes are centralized and occur one by one in a strict order.

3.Changes are made with pure functions: In order to specify how the state tree is transformed by actions, you need pure functions. Pure functions are those whose return values depend solely on the values of their arguments. Reducers are just pure functions that take the previous state and an action and return the next state. You can have a single reducer in your application and as it grows, you can split it off into smaller reducers. These smaller reducers will then manage specific parts of the state tree.

Advantages Of Redux – React Redux Tutorial

Following are some of the major advantages of Redux:
**Predictability of outcome – **Since there is always one source of truth, i.e. the store, there is no confusion about how to sync the current state with actions and other parts of the application.**Maintainability – **The code becomes easier to maintain with a predictable outcome and strict structure.Server side rendering – You just need to pass the store that is created on the server, to the client side. This is very useful for initial render and provides a better user experience as it optimizes the application performance.**Developer tools – **From actions to state changes, developers can track everything going on in the application in real time.**Community and ecosystem – **Redux has a huge community behind it which makes it even more captivating to use. A large community of talented individuals contribute to the betterment of the library and develop various applications with it.**Ease of testing – **Redux code are mostly functions which are small, pure and isolated. This makes the code testable and independent.**Organization – **Redux is very precise about how the code should be organized, this makes the code more consistent and easier when a team works with it.## Components Of Redux – React Redux Tutorial

Redux has four components.

  1. Action
  2. Reducer
  3. Store
  4. View

Let us discuss them in detail:

**Action – **The only way to change state content is by emitting an action. Actions are the plain JavaScript objects which are the main source of information used to send data (user interactions, internal events such as API calls, and form submissions) from the application to the store. The store receives information only from the actions. You have to send the actions to the store using store.dispatch().

Internal actions are simple JavaScript objects that have a** type** property (usually String constant), describing the type of action and the entire information being sent to the store.

{
    type: ADD_TODO,
    text
}

Actions are created using action creators which are the normal functions that return actions.

function addTodo(text) {
    return {
        type: ADD_TODO,
        text
    }
}

To call actions anywhere in the app, use **dispatch()**method:

dispatch(addTodo(text));

**Reducer – **Actions describe the fact that something happened, but don’t specify how the application’s state changes in response. This is the job of reducers. It is based on the array reduce method, where it accepts a callback (reducer) and lets you get a single value out of multiple values, sums of integers, or an accumulation of streams of values. In Redux, reducers are functions (pure) that take the current state of the application and an action and then return a new state. Understanding how reducers work is important because they perform most of the work.

function reducer(state = initialState, action) {
    switch (action.type) {
        case ADD_TODO:
            return Object.assign({}, state,
                { todos: [ ...state.todos,
                    {
                        text: action.text,
                        completed: false
                    }
                    ]
                })
        default:
            return state
    }
}

**Store – **A store is a JavaScript object which can hold the application’s state and provide a few helper methods to access the state, dispatch actions and register listeners. The entire state/ object tree of an application is saved in a single store. As a result of this, Redux is very simple and predictable. We can pass middleware to the store to handle processing of data as well as to keep a log of various actions that change the state of stores. All the actions return a new state via reducers.

import { createStore } from 'redux'
import todoApp from './reducers'
 
let store = createStore(reducer);

**View – **Smart and dumb components together build up the view. The only purpose of the view is to display the date passed down by the store. The smart components are in charge of the actions. The dumb components underneath the smart components notify them in case they need to trigger the action. The smart components, in turn, pass down the props which the dumb components treat as callback actions.
Following is a diagram which shows how the data actually flows through all the above-described components in Redux.

React With Redux – React Redux Tutorial

Now that you are familiar with Redux and its components, let’s now see how you can integrate it with a React application.

**STEP 1: **You need to setup the basic react, webpack, babel setup. Following are the dependencies we are using in this application.

"dependencies": {
  "babel-core": "^6.10.4",
  "babel-loader": "^6.2.4",
  "babel-polyfill": "^6.9.1",
  "babel-preset-es2015": "^6.9.0",
  "babel-preset-react": "^6.11.1",
  "babel-register": "^6.9.0",
  "cross-env": "^1.0.8",
  "css-loader": "^0.23.1",
  "expect": "^1.20.1",
  "node-libs-browser": "^1.0.0",
  "node-sass": "^3.8.0",
  "react": "^15.1.0",
  "react-addons-test-utils": "^15.1.0",
  "react-dom": "^15.1.0",
  "react-redux": "^4.4.5",
  "redux": "^3.5.2",
  "redux-logger": "^2.6.1",
  "redux-promise": "^0.5.3",
  "redux-thunk": "^2.1.0",
  "sass-loader": "^4.0.0",
  "style-loader": "^0.13.1",
  "webpack": "^1.13.1",
  "webpack-dev-middleware": "^1.6.1",
  "webpack-dev-server": "^1.14.1",
  "webpack-hot-middleware": "^2.11.0"
},

STEP 2: Once you are done with installing the dependencies, then create** components folder in src **folder. Within that create App.js file.

import React from 'react';
import UserList from '../containers/user-list';
import UserDetails from '../containers/user-detail';
require('../../scss/style.scss');
 
const App = () => (
    <div>
        <h2>User List</h2>
        <UserList />
        <hr />
        <h2>User Details</h2>
        <UserDetails />
    </div>
);
 
export default App;

**STEP 3: **Next create a new actions folder and create index.js in it.

export const selectUser = (user) => {
    console.log("You clicked on user: ", user.first);
    return {
        type: 'USER_SELECTED',
        payload: user
    }
};

STEP 4: Now create** user-details.js **in a new folder called containers.

import React, {Component} from 'react';
import {connect} from 'react-redux';
 
class UserDetail extends Component {
    render() {
        if (!this.props.user) {
            return (<div>Select a user...</div>);
        }
        return (
            <div>
                <img height="150" width="150" src={this.props.user.thumbnail} />
                <h2>{this.props.user.first} {this.props.user.last}</h2>
                <h3>Age: {this.props.user.age}</h3>
                <h3>Description: {this.props.user.description}</h3>
            </div>
        );
    }
}
 
function mapStateToProps(state) {
    return {
        user: state.activeUser
    };
}
 
export default connect(mapStateToProps)(UserDetail);

STEP 5: Inside the same folder create user-list.js file.

import React, {Component} from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {selectUser} from '../actions/index'
class UserList extends Component {
    renderList() {
        return this.props.users.map((user) => {
            return (
                <li key={user.id}
                    onClick={() => this.props.selectUser(user)}
                >
                    {user.first} {user.last}
                </li>
            );
        });
    }
    render() {
        return (
            <ul>
                {this.renderList()}
            </ul>
        );
    }
}
function mapStateToProps(state) {
    return {
        users: state.users
    };
}
function matchDispatchToProps(dispatch){
    return bindActionCreators({selectUser: selectUser}, dispatch);
}
export default connect(mapStateToProps, matchDispatchToProps)(UserList);

STEP 6: Now create reducers folder and create index.js within it.

import {combineReducers} from 'redux';
import UserReducer from './reducer-users';
import ActiveUserReducer from './reducer-active-user';
 
const allReducers = combineReducers({
    users: UserReducer,
    activeUser: ActiveUserReducer
});
export default allReducers

STEP 7: Within the same** reducers** folder, create **reducer-users.js **file.

export default function () {
    return [
        {
            id: 1,
            first: "Maxx",
            last: "Flinn",
            age: 17,
            description: "Loves basketball",
            thumbnail: "https://goo.gl/1KNpiy"
        },
        {
            id: 2,
            first: "Allen",
            last: "Matt",
            age: 25,
            description: "Food Junky.",
            thumbnail: "https://goo.gl/rNLgwv"
        },
        {
            id: 3,
            first: "Kris",
            last: "Chen",
            age: 23,
            description: "Music Lover.",
            thumbnail: "https://goo.gl/EVbPHb"
        }
    ]
}

**STEP 8: **Now within reducers folder create a reducer-active-user.js file.

export default function (state = null, action) {
    switch (action.type) {
        case 'USER_SELECTED':
            return action.payload;
            break;
    }
    return state;
}

**STEP 9: **Now you need to create index.js in the root folder.

import 'babel-polyfill';
import React from 'react';
import ReactDOM from "react-dom";
import {Provider} from 'react-redux';
import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import promise from 'redux-promise';
import createLogger from 'redux-logger';
import allReducers from './reducers';
import App from './components/App';
 
const logger = createLogger();
const store = createStore(
    allReducers,
    applyMiddleware(thunk, promise, logger)
);
 
ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root')
);

STEP 10: Now that you are done writing the codes, launch your application at localhost:3000.

This brings us to the end of the blog on React Redux tutorial. I hope through this React Redux tutorial blog I was able to clearly explain what is Redux, its components and why we use it with React. You can refer to this blog on ReactJS Tutorial, in case you want to learn more about React.

Understanding React with Redux and Redux Thunk for Beginners

Understanding React with Redux and Redux Thunk for Beginners

Introduction

Redux, according to the offical docs, is a predictable state container for JavaScript apps written by Dan Abramov. It’s a lightweight implementation of Flux, which is another library for managing the state. Basically Redux took the ideas that Flux brought in, leaving out its complexity by “borrowing” things from Elm.

For starters, there are several key concepts to understand: store, actions / action creators, and reducers. The official documentation is pretty straightforward and also plenty of examples and nice analogies can be found on the internet.

Principles

Redux has three fundamental principles:

  • single source of truth

The whole state of the application is stored in an object tree (within a single store). Visualize the state as a “model”, but without setters. As a plus, a single state tree enables us to debug our application with ease.

  • state is read-only

In order to modify state in Redux, actions have to be dispatched. Actions are a plain JavaScript object that describe what changed, sending data from the application to the store.

An action will look like this:

{
      type: 'ACTION_TYPE',
      action_value: string
  }

  • changes are made with pure functions

In order to tie state and actions together, we write a function called a reducer that takes two parameters: the (soon to be previous) state and an action. This pure function applies the action to that state and returns the desired next state.

Example of a reducer:

 export function reducer(state = '', action) {
      switch (action.type) {
          case 'ACTION_TYPE':
              return action.action_value;
          default:
              return state;
      }
  } 

Important: Reducers do not store state, and they do not mutate state. You pass state to the reducer and the reducer will return state.

Tip: As a best practice, even though it’s possible to have a single reducer that manages the transformation done by every action, it is better to use reducer composition - breaking down the reducer into multiple, smaller reducers, each of them handling a specific slice of the application state.

How it works

When one action is dispatched to the store, the combined reducer catches the action and sends it to each of the smaller reducers. Each smaller reducer examines what action was passed and dictates if and how to modify that part of state. You will find an example of a combined reducer a bit later in the article.

After each smaller reducer produces its corresponding next state, an updated state object will be saved in the store. Because this is important, I’m mentioning again that the store is the single source of truth in our application. Therefore, when each action is run through the reducers, a new state is produced and saved in the store.

Besides all of this, Redux comes up with another concept, action creators, which are functions that return actions. These can be linked to React components and when interacting with your application, the action creators are invoked (for example in one of the lifecycle methods) and create new actions that get dispatched to the store.

 export function actionCreator(bool) {
        return {
            type: 'ACTION_TYPE',
            action_value: bool
        };
    }

Fetching data from an API

Now onto our application. All of the above code snippets were just examples. We will now dive into the important bits of the code of our app. Also, a github repo will be available at the end of the article, containing the entire app.

Our app will fetch (asynchronously) data that is retrieved by an API - assuming we already built and deployed a working API, how convenient :) - and then display the fetched data as nice as my UI design skills go (not too far).

TVmaze’s public API contains tonnes of data and we will fetch all the shows they have ever aired. Then, the app will display all the shows, toghether with their rating and premiere date.

Designing our state

In order for this application to work properly, our state needs to have 3 properties: isLoading, hasError and items. So we will have one action creator for each property and an extra action creator where we will fetch the data and call the other 3 action creators based on the status of our request to the API.

Action creators

Let’s have a look at the first 3 action creators

export function itemsHaveError(bool) {
        return {
            type: 'ITEMS_HAVE_ERROR',
            hasError: bool
        };
    }

    export function itemsAreLoading(bool) {
        return {
            type: 'ITEMS_ARE_LOADING',
            isLoading: bool
        };
    }

    export function itemsFetchDataSuccess(items) {
        return {
            type: 'ITEMS_FETCH_DATA_SUCCESS',
            items
        };
    }

The first 2 action creators will receive a bool as a parameter and they will return an object with that bool value and the corresponding type.

The last one will be called after the fetching was successful and will receive the fetched items as an parameter. This action creator will return an object with a property called items that will receive as value the array of items which were passed as an argument. Instead if items: items, we can just write items, using an ES6 syntactic sugar called property shorthand.

To visualize a bit what was described earlier, this is how it looks in Redux DevTools:

Out of the box, action creators can return just actions. That’s where Redux Thunk comes in handy. Thunk allows us to have action creators that return a function instead of an action and dispatch an action only in certain cases.

If it wasn’t for Redux Thunk, we would probably end up having just one action creator, something like this:

export function itemsFetchData(url) {
        const items = axios.get(url);

        return {
            type: 'ITEMS_FETCH_DATA',
            items
        };
    }

Obviously, it would be a lot harder in this scenario to know if the items are still loading or checking if we have an error.

Knowing these and using Redux Thunk, our action creator will be:

 export function itemsFetchData(url) {
        return (dispatch) => {
            dispatch(itemsAreLoading(true));

            axios.get(url)
                .then((response) => {
                    if (response.status !== 200) {
                        throw Error(response.statusText);
                    }

                    dispatch(itemsAreLoading(false));

                    return response;
                })
                .then((response) => dispatch(itemsFetchDataSuccess(response.data)))
                .catch(() => dispatch(itemsHaveError(true)));
        };
    }

Reducers

Now that we have our action creators in place, let’s start writing our reducers.

All reducers will be called when an action is dispatched. Because of this, we are returning the original state in each of our reducers. When the action type matches, the reducer does what it has to do and returns a new slice of state. If not, the reducer returns the original state back.

Each reducer takes 2 parameters: the (soon to be previous) slice of state and an action object:

export function itemsHaveError(state = false, action) {
        switch (action.type) {
            case 'ITEMS_HAVE_ERROR':
                return action.hasError;
            default:
                return state;
        }
    }

    export function itemsAreLoading(state = false, action) {
        switch (action.type) {
            case 'ITEMS_ARE_LOADING':
                return action.isLoading;
            default:
                return state;
        }
    }

    export function items(state = [], action) {
        switch (action.type) {
            case 'ITEMS_FETCH_DATA_SUCCESS':
                return action.items;
            default:
                return state;
        }
    }

Now that we have the reducers created, let’s combine them in our index.js from our reducers folder:

 import { combineReducers } from 'redux';
    import { items, itemsHaveError, itemsAreLoading } from './items';

    export default combineReducers({
        items,
        itemsHaveError,
        itemsAreLoading
    });

Creating the store

Don’t forget about including the Redux Thunk middleware in the configureStore.js:


 import { createStore, applyMiddleware } from 'redux';
    import thunk from 'redux-thunk';
    import rootReducer from '../reducers';

    export default function configureStore(initialState) {
        const composeEnhancers = 
            window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
                window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
                    // options like actionSanitizer, stateSanitizer
                }) : compose;

        const enhancer = composeEnhancers(
            applyMiddleware(thunk)
        );

        return createStore(
            rootReducer,
            initialState,
            enhancer
        );
    }

Using the store in our root index.js

 import React from 'react';
    import { render } from 'react-dom';
    import { Provider } from 'react-redux';
    import configureStore from './store/configureStore';

    import ItemList from './components/ItemList';

    const store = configureStore();

    render(
        <Provider store={store}>
            <ItemList />
        </Provider>,
        document.getElementById('app')
    );

Writing our React component which shows the fetched data

Let’s start by talking about what we are importing here.

In order to work with Redux, we have to import connect from ‘react-redux’:

    import { connect } from 'react-redux';

Also, because we will fetch the data in this component, we will import our action creator that fetches data:

    import { itemsFetchData } from '../actions/items';

We are importing only this action creator, because this one also dispatches the other actions to the store.

Next step would be to map the state to the components’ props. For this, we will write a function that receives state and returns the props object.

const mapStateToProps = (state) => {
        return {
            items: state.items,
            hasError: state.itemsHaveError,
            isLoading: state.itemsAreLoading
        };
    };

When we have a new state, the props in our component will change according to our new state.

Also, we need to dispatch our imported action creator.

    const mapDispatchToProps = (dispatch) => {
        return {
            fetchData: (url) => dispatch(itemsFetchData(url))
        };
    };


With this one, we have access to our itemFetchData action creator through our props object. This way, we can call our action creator by doing this.props.fetchData(url);

Now, in order to make these methods actually do something, when we export our component, we have to pass these methods as arguments to connect. This connects our component to Redux.

    export default connect(mapStateToProps, mapDispatchToProps)(ItemList);

Finally, we will call this action creator in the componentDidMount lifecycle method:

    this.props.fetchData('http://api.tvmaze.com/shows');


Side note: if you are wondering why are we calling the action creator in componentDidMount instead of other lifecycle methods, I have found a couple of good reasons here:

  • You can’t guarantee the AJAX request won’t resolve before the component mounts. If it did, that would mean that you’d be trying to setState on an unmounted component, which not only won’t work, but React will yell at you for. Doing AJAX in componentDidMount will guarantee that there’s a component to update.

  • Fiber, the next implementation of React’s reconciliation algorithm, will have the ability to start and stop rendering as needed for performance benefits. One of the trade-offs of this is that componentWillMount, the other lifecycle event where it might make sense to make an AJAX request, will be “non-deterministic”. What this means is that React may start calling componentWillMount at various times whenever it feels like it needs to. This would obviously be a bad formula for AJAX requests.

Besides this, we need some validations:

    if (this.props.hasError) {
        return <p>Sorry! There was an error loading the items</p>;
    }

    if (this.props.isLoading) {
        return <p>Loading ...</p>;
    }


And the actual iteration over our fetched data array:

 {this.props.items.map((item) => (
        // display data here
    ))}

In the end, our component will look like this:

 import React, { Component, PropTypes } from 'react';
    import { connect } from 'react-redux';
    import { ListGroup, ListGroupItem } from 'react-bootstrap';
    import { itemsFetchData } from '../actions/items';

    class ItemList extends Component {
        componentDidMount() {
            this.props.fetchData('http://api.tvmaze.com/shows');
        }

        render() {
            if (this.props.hasError) {
                return <p>Sorry! There was an error loading the items</p>;
            }

            if (this.props.isLoading) {
                return <p>Loading ...</p>;
            }

            return (
                <div style={setMargin}>
                    {this.props.items.map((item) => (
                        <div key={item.id}>
                                <ListGroup style={setDistanceBetweenItems}>
                                    <ListGroupItem href={item.officialSite} header={item.name}>
                                        Rating: {item.rating.average}
                                        <span className="pull-xs-right">Premiered: {item.premiered}</span>
                                    </ListGroupItem>
                                </ListGroup>
                        </div>
                    ))}
                </div>
            );
        }
    }

    ItemList.propTypes = {
        fetchData: PropTypes.func.isRequired,
        items: PropTypes.array.isRequired,
        hasError: PropTypes.bool.isRequired,
        isLoading: PropTypes.bool.isRequired
    };

    const mapStateToProps = (state) => {
        return {
            items: state.items,
            hasError: state.itemsHaveError,
            isLoading: state.itemsAreLoading
        };
    };

    const mapDispatchToProps = (dispatch) => {
        return {
            fetchData: (url) => dispatch(itemsFetchData(url))
        };
    };

    export default connect(mapStateToProps, mapDispatchToProps)(ItemList);

And that was all !

Our app will look like this:

I wasn’t lying about my design skills, was I ? :)

Last words and other resources

We now have an app that is fetching data asynchronously from an API, using React for our UI and Redux for managing the state of our application. I think this is a good starting point for a personal / small project and also you get to work with new technologies.

This doesn’t mean that Redux is the solution for every problem we face when writing apps in React or that Redux is a a must-use in any Javascript written project, as Dan Abramov states in an interesting article.

Also worth noting, Facebook are preparing React Fiber, a reimplementation of React. They state that its goal is to make it more suitable for animations and gestures and that the key new feature will be incremental rendering which is:

  • the ability to split rendering work into chunks and spread it out over multiple frames