A Guide To React, Redux, Router (Latest Version)

Introduction

react redux thunk router

A step-wise-step guide to create frontend app in React, Redux, Router.

React is a frontend library used to create Single Page Application (SPA).

Redux is a state management library. When your project grows larger, it is difficult to handle all the states used in your app. Hence, you need a store, which keeps all your state, and actions.

Router performs routing in client app, however it is still a single page app.

So, let’s begin.

Prepare Layout For Your App

Start with creating a directory

mkdir react-redux
cd react-redux

I have used yarn for package management. If you haven’t installed yarn, you can go with npm

yarn init

You can choose any value you like, however I have left default for everything.

Now, update your package.json file with following lines of code:

{
  "name": "react-redux",
  "version": "1.0.0",
  "license": "MIT",
  "private": true,
  "scripts": {
    "start": "react-scripts start",
    "now-start": "serve -s ./build",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject",
    "precommit": "pretty-quick --staged"
  },
  "devDependencies": {
    "prettier": "1.18.2",
    "react-scripts": "3.0.1"
  },
  "dependencies": {
    "axios": "^0.19.0",
    "connected-react-router": "6.5.2",
    "react": "16.8.6",
    "react-dom": "16.8.6",
    "react-redux": "7.1.0",
    "react-router": "5.0.1",
    "react-router-dom": "5.0.1",
    "redux": "4.0.4",
    "redux-thunk": "2.3.0",
    "sanitize.css": "11.0.0",
    "serve": "11.1.0"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]
}

You can learn more about package.json file in here: Creating A Package.json File

If you want to know what the packages in the package.json file do, you can view their documentation.
 
Now, install the packages by following command:
yarn install
Create two directories in project root folder as:
mkdir public
mkdir src
public folder contains the html file which is served in the server, an icon and a web manifest file. Go to your public directory:
cd public
Let’s, create an html file index.html and paste the following code:
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="theme-color" content="#000000">
  <!--
      manifest.json provides metadata used when your web app is added to the
      homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
    -->
  <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
  <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
  <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
  <title>React App</title>
</head>

<body>
  <noscript>
    You need to enable JavaScript to run this app.
  </noscript>
  <div id="root"></div>
  <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
</body>

</html>

Copy your favicon.ico icon file to the folder. Then, create a manifest.json file inside the folder.
Paste following inside the manifest.json:

{
  "short_name": "React + Redux App",
  "name": "Create React App Redux",
  "icons": [
    {
      "src": "favicon.ico",
      "sizes": "64x64 32x32 24x24 16x16",
      "type": "image/x-icon"
    }
  ],
  "start_url": "./index.html",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}

Now, change the directory to src

cd src

This folder contains all the javascript source files used in the client app.

You can create an index.css file which will contain your css stylings.

Now, create an index.js file which will be the entry point to your client app. Paste the following codes:

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { ConnectedRouter } from 'connected-react-router'
import App from './containers/app'
import { Route, Switch } from 'react-router-dom'

import 'sanitize.css/sanitize.css'
import './index.css'
import configureStore, { history } from './configureStore';

const store = configureStore()

const target = document.querySelector('#root')

render(
  <Provider store={store}>
    <ConnectedRouter history={history}>
      <>
        <App />
        <Switch>
          {/* Your Route Goes Here like this
            <Route exact path='/' component={Home} />
          */}
        </Switch>
      </>
    </ConnectedRouter>
  </Provider>,
  target
)

Up to this we created our layout. Now, let’s create a store using redux.

Let’s configure our store. Create configureStore.js inside src folder. Paste the following code:

import { createBrowserHistory } from 'history'
import { applyMiddleware, compose, createStore } from 'redux'
import thunk from 'redux-thunk'
import { routerMiddleware } from 'connected-react-router'
import createRootReducer from './reducers'

export const history = createBrowserHistory()

const enhancers = []

if (process.env.NODE_ENV === 'development') {
    const devToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION__
  
    if (typeof devToolsExtension === 'function') {
      enhancers.push(devToolsExtension())
    }
  }

export default function configureStore(preloadedState) {
    const store = createStore(
        createRootReducer(history),
        preloadedState,
        compose(
            applyMiddleware(
                thunk,
                routerMiddleware(history),
            ),
            ...enhancers
        )
    )
    return store
}

You do not need to edit above mentioned files till now, however you need reducers where your states and actions are stored. 

Reducers

Create a folder named reducers 

mkdir reducers
cd reducers

Now, create an index.js file inside reducers and paste the following lines of code:

import { combineReducers } from 'redux'
import { connectRouter } from 'connected-react-router'
import counter from './counter'

export default (history) => combineReducers({
    router: connectRouter(history),
    counter
    // Register your reducers here
})

Then, create a reducer counter.js as an example inside the reducers folder and paste the following code:

export const INCREMENT_REQUESTED = 'counter/INCREMENT_REQUESTED'
export const INCREMENT = 'counter/INCREMENT'
export const DECREMENT_REQUESTED = 'counter/DECREMENT_REQUESTED'
export const DECREMENT = 'counter/DECREMENT'

const initialState = {
  count: 0,
  isIncrementing: false,
  isDecrementing: false
}

export default (state = initialState, action) => {
  switch (action.type) {
    case INCREMENT_REQUESTED:
      return {
        ...state,
        isIncrementing: true
      }

    case INCREMENT:
      return {
        ...state,
        count: state.count + 1,
        isIncrementing: !state.isIncrementing
      }

    case DECREMENT_REQUESTED:
      return {
        ...state,
        isDecrementing: true
      }

    case DECREMENT:
      return {
        ...state,
        count: state.count - 1,
        isDecrementing: !state.isDecrementing
      }

    default:
      return state
  }
}

export const increment = () => {
  return dispatch => {
    dispatch({
      type: INCREMENT_REQUESTED
    })

    dispatch({
      type: INCREMENT
    })
  }
}

export const incrementAsync = () => {
  return dispatch => {
    dispatch({
      type: INCREMENT_REQUESTED
    })

    return setTimeout(() => {
      dispatch({
        type: INCREMENT
      })
    }, 3000)
  }
}

export const decrement = () => {
  return dispatch => {
    dispatch({
      type: DECREMENT_REQUESTED
    })

    dispatch({
      type: DECREMENT
    })
  }
}

export const decrementAsync = () => {
  return dispatch => {
    dispatch({
      type: DECREMENT_REQUESTED
    })

    return setTimeout(() => {
      dispatch({
        type: DECREMENT
      })
    }, 3000)
  }
}

Now, go to previous directory and create a new folder named containers:

cd ..
mkdir containers
cd containers

Create your layouts here. I personally suggest you to create a new folder for each container rather than keeping every files in a single directory. In this way, it is easier to organise your code. That means, instead of making a Home.js file, you should create a directory named home and inside it, create a file index.js. Doing so, you can import the home container from other places as 

import Home from 'home'
// Use relative path. I hope you get it

You can get this code from my github repo:

https://github.com/kriss-u/react-redux-router

git clone https://github.com/kriss-u/react-redux-router.git

If you like to know about web programming in Django, whether you should do it or not, you can check it out here:

Django – A Full Stack Web Programming – Should I use it?

3 thoughts on “A Guide To React, Redux, Router (Latest Version)”

Leave a Reply

%d bloggers like this: