Introduction
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
yarn install
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
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: