loading...

React Authentication App Using Redux And Sagas

srivasthava12 profile image Srivasthava12 ・4 min read

Overview

The things that I am going to go through in this post are:

We will be visiting the above-mentioned points while we are working on our Auth app.
Let's establish the fact that Redux is not related to React. Redux can be used in Angular too. Said that, Redux gels with React impeccably. So, let me answer the question what is redux?
To keep it simple Redux is “open-source JavaScript library for managing application state”. It helps you write applications that behave consistently.

To spice this up let’s use real API’s. You can use the backend API service that I have in my repo i.e.., Authentication with Node and follow the instructions mentioned in README file to run the service or you could use your own json web token based API.

Let the show begin!!

Alt Text

To start the show we have to stage our react app. To do so follow the commands.

Make sure you have create-react-app installed
a) $ npm install -g create-react-app

Create react app
b) $ npx create-react-app my-app

Move into the directory my-app
c) $ cd my-app

Run the react app
d)$ npm start

Let's install all the required pacakges
e)$ npm i redux react-redux redux-saga react-router redux-form --save

Now you have staged your react app. So, let's dive in.

In code directory. The rundown of the structure is given below:

src/  
  login/       
    actions.js
    constants.js
    sagas.js
    selector.js
    reducer.js
    index.js
    components/
             login.js
  register/
    actions.js      
    constants.js
    sagas.js
    selector.js
    reducer.js
    index.js
    components/
             register.js

  user/
    reducer.js
    actions.js
    constants.js

  share/
    Messages.js

  helpers/
    api-errors.js
    check-auth.js

Main.js
index-reducer.js  
index-sagas.js  

Let's go throught the folder and files we have just created:
login/, register/ & user/
login/ & register/ are the routes that we are going to use.

Now coming to the files that we created:
a) actions.js are payloads of information that send data from your application to your store. They are plain Javascript object
b) reducer.js specify how the application's state changes in response to sent to the store.
c) constants.js the place where we will have our constants for actions and reducers
d)sagas.js this is where we manage the impure operations i.e. asynchronous things like data fetching
e) index-reducer.js & index-sagas.js are the hub where we combile all reducers and sagas

let's go into the code

1) In the directory src/index

  • The whole code for index.js is:
import React from 'react';
import ReactDOM from 'react-dom';
import { applyMiddleware, createStore, compose } from 'redux';
import { Provider } from 'react-redux';
import createSagaMiddleware from 'redux-saga';
import { routerMiddleware } from 'react-router-redux';
import { history } from './history';
import { Router } from 'react-router-dom';

// Import all of our components
import App from './App';
import './index.css';

// Import the index reducer and sagas
import IndexReducer from './index-reducer';
import IndexSagas from './index-sagas';

import registerServiceWorker from './registerServiceWorker';

// Setup the middleware to watch between the Reducers and the Actions
const sagaMiddleware = createSagaMiddleware();

const routersMiddleware = routerMiddleware(history);

/*eslint-disable */
const composeSetup =
    process.env.NODE_ENV !== 'production' && typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
        ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
        : compose;
/*eslint-enable */

const store = createStore(
    IndexReducer,
    composeSetup(applyMiddleware(sagaMiddleware, routersMiddleware)) // allows redux devtools to watch sagas
);

// Begin our Index Saga
sagaMiddleware.run(IndexSagas);

ReactDOM.render(
    <Provider store={store}>
        <Router history={history}>
            <App />
        </Router>
    </Provider>
    document.getElementById('root')
);
registerServiceWorker();

  • Now let's go throught the above boiler code
   import React from 'react';
  import ReactDOM from 'react-dom';
  import { applyMiddleware, createStore, compose } from 'redux';
  import { Provider } from 'react-redux';
  import createSagaMiddleware from 'redux-saga';
  import { routerMiddleware } from 'react-router-redux';
  import { history } from './history';
  import { Router } from 'react-router-dom';

  // Import all of our components
  import App from './App';
  import './index.css';

  // Import the index reducer and sagas
  import IndexReducer from './index-reducer';
  import IndexSagas from './index-sagas';
import the required pakages
  • Middleware

    const  sagaMiddleware  =  createSagaMiddleware()
    const  routersMiddleware  =  routerMiddleware(history);
    

Creates a Redux middleware and connects the Sagas to the Redux Store

  • Creating a Store

    /*eslint-disable */
    const composeSetup = process.env.NODE_ENV !== 'production' && typeof window === 'object' &&
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : compose
    /*eslint-enable */
    

const store = createStore(
IndexReducer,
composeSetup(applyMiddleware(sagaMiddleware, routersMiddleware)),
)




 Here ` composeSetup(applyMiddleware(sagaMiddleware, routersMiddleware)),` allows redux to watch sagas and router

+ To Start the Saga middleware



  ```javascript
  sagaMiddleware.run(IndexSagas)

Can run only after the applyMiddleware phase.

  • Now let's Render the Index.js
  ReactDOM.render(
    <Provider  store={store}>
      <Router  history={history}>
        <App  />
      </Router>
    </Provider>,
    document.getElementById('root')
  );
  registerServiceWorker();

So here we are Providing react app with a store, get it providing store <Provider store={store}>

2) Now let's get into index-reducer.js

 ```javascript 
 import { combineReducers } from  'redux'
 import { reducer  as  form } from  'redux-form'

 const  IndexReducer  =  combineReducers({
        form
 })
 export  default  IndexReducer
 ```

The combineReducers helper function turns an object whose values are different reducing functions into a single reducing function you can pass to createStore

3) Lets get in to index-saga.js

import { all } from  'redux-saga/effects';
export  default  function*  IndexSaga() {
yield  all([ ]);
}

4) Now that we have done with indexes of the reducers, saga and the main Index lets get in to App.js :

import  React, { Component } from  'react';
import  './App.css';
import  Main  from  './Main';
class  App  extends  Component {
  render() {
    return (
      <div  className="App">
        <Main  />
      </div>
    );
  }
}
export  default  App;

Here in App, <Main /> is where our routes exist

5) We have separated a component to deal with the routes of the application i.e. the Main Component

import React from 'react';
import { Switch, Route } from 'react-router-dom';
import Login from '../src/login';
import Register from '../src/register';

export default class Main extends React.Component {
    render() {
        return (
            <main>
                <Switch>
                    <Route path="/login" component={Login} />
                    <Route path="/register" component={Register} />
                </Switch>
            </main>
        );
    }
}

Let's dig in,
Switch
<Switch> is unique in that it renders a route exclusively. In contrast, every <Route> that matches the location renders inclusively.

Discussion

pic
Editor guide