Great we have our authentication setup, now we will first setup redux which will be our global state that we will access through out the application.

But before that I would recommend you try the previous step where we setup Auth0.

Here is the redux documentation.

Here is a couple of article explaining the difference between redux, and passing state from parent to child and a simple example implementing redux.

Let setup our directories, We will have another directory in our src folder since redux is a state management and has nothing to do with the backend. We will create a redux folder, and within that folder we will create store.js and reducer.js.

cd src
mkdir redux
cd redux
touch store.js reducer.js

Great let’s setup redux, the two modules we will be using is redux, and react redux. Redux module is responsible for setting up your store and reducer. Then react-redux is for connecting react component to redux. Before we connect our component to redux, we will first setup our redux reducer then our store.

Go to your reducer.js file in your redux folder, and create a initialState object which will the default global state, if state is not manipulated it will return it’s default state. For now we will just have a user property for when we retrieve the user data from auth0.

//Define your initialState that will be used for the reducer.const initialState = {user: null}

We will define our action type which will be constants or variables that are uppercase. These will be used with the reducer. with a switch statement, and each action should return a action type. We will have LOGIN, and LOGOUT for when the user logs in and when a user logs out.

//Define your action types.const LOGIN = "LOGIN";const LOGOUT = "LOGOUT";

Now lets define our reducer which will contain a switch statement, which will return a new state based on the action’s type. We will define our reducer as a default export, so there will be no need to name it. By default it will return the state, else if it’s action type is LOGIN or LOGOUT manipulate the state accordingly.

//When doing a default export with a reducer which is essentially a function with a state and action argument, with the state default set to initialState.export default (state=initialState, action) => {//Do a switch statement on the action.type, and set the state base on the action's typeswitch(action.type) {//Have the login action type that will set the initialState user property to the action's payload.case LOGIN://Use the spread to pass in the values of the initialState, and set the new property user.return {...state, user: action.payload};//Have the logout action type that will set the initialState user property to null when user's logs out.case LOGOUT://Use the spread to pass in the values of the initialState, and set the new property user to it's default value(null).return {...state, user: null};default://if there is not action type return the state by default.return state;}}

For login we set the action.payload to user from the action, and in the logout we give user it’s default state.

When we define our actions we will return an object that will have to contain a type(which will be the action type) and if you need one a payload. First let’s define our login action that will login the user based on the userInfo argument pass into action that will be returned as the payload.

//Export the function that will login the user to it's initialState.export const login = (userInfo) => {return {type: LOGIN,payload: userInfo}}

Then we will do logout in which we do not a payload since we just simply logging out the user from state.

//Export the function that will logs the user out from state.export const logout = () => {return {type: LOGOUT}}

Now we will now define the store. Go to your store.js file, and import a named export called createStore from redux which will be responsible for creating the store. Then import your reducer from your reducer.js file.

//Import the reducer to export it with the reducer.import reducer from './reducer';//import createStore that will create a store from redux.import { createStore } from 'redux';

Since we are gonna default export our store we will export the store using createStore the reducer as first argument and optionally import the redux devtools. Here is the redux devtools github.

//Export the reducer with redux devtoolsexport default createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());

Now our redux is setup let now configure our components.

We will go to index.js file in our src folder and import the named export Provider from react-redux. Also our store from our store.js file in our redux folder.

import { Provider } from 'react-redux';
import store from './redux/store';

Then we will wrap our BrowserRouter with the store.It connect to the store via the store prop in within the parathesis of the ReactDOM.render.

ReactDOM.render(<Provider store={store}><BrowserRouter><App /></BrowserRouter></Provider>, document.getElementById('root'));

Now let’s use react-redux named export connect which will is a method to connect all of our components to redux.

First lets connect our app component in our App.js using the connect method.

import { connect } from 'react-redux';

Then we will conditionally set the user state in redux or set to null using our login and logout actions. They are two ways to dispatch actions in redux one is via mapDispatchToProps which will map our actions to props or just use the dispatch prop, and invoking our action as callback to the dispatch. But first import our actions.

//import actions that will be implemented in your reducer.import { login, logout } from './redux/reducer';

Now in our componentDidMount we will check if the user session is defined, if it is we will login our user if it isn’t we will log them out of redux therefore setting it null.

//In it's componentDidMount  get the session, and if it has data set your intialState user to it.componentDidMount() {axios.get('/api/user-data').then(res => {//Destruct the dispatch props from this.props that will be responsible for dispatching or initiating actions from your reducer.const { dispatch } = this.props;if(res.data.user) {//Dispatch the login function with the user data.dispatch(login(res.data.user));//Else logout the user from the intialState.} else {//Dispatch the logout the user by default if there is no data in session.dispatch(logout());}})}

Then we will just delete the export the component connected with redux, since we are using react-router-dom in order to have access we need wrap our connect withRouter in order access the props from react-router-dom.

export default withRouter(connect()(App));

Lets start with the Navbar which will need access to the user state to conditionally the render the login/logout link. With the logout link have the users picture right next to it.

import { connect } from 'react-redux';

Great our navbar is connected, next we are gonna use mapStateToProps. Which will map the specified or all of the state from the reducer and map it to props of the component.

In this case we need the user state so we can access it with state.user.

const mapStateToProps = state => {  return {   user: state.user  }}

Now we have access in to our user prop when we login, lets delete our export default before our component. Then export default our component connected to redux, and also use with router to have access to the props of react-router-dom.

//Then wrap our Component with the HOC, and the connect double invoked.export default withRouter(connect(mapStateToProps)(Navbar));

Now our component is connected.

Let’s define our logout function . Which will destroy the session and logout the user from the reducer’s state. We will do a axios.post(api/logout) and past an empty since we don’t need any data. We are just gonna destroy the session. Then we will refresh the browser to update the navbar to have login instead of logout, using this.props.history.go().

//Logout function that will logout hte user from the initialState.logout = () => { //Pass a empty since you are just logging out the user. axios.post('/api/logout', {}) .then(res => { //The will logout a user alert(res.data.message);  //Reload the browser using this.props.history.go();  this.props.history.go(); }).catch(err => console.log('Logout Axios Error-------', err));}

Great let’s finish it off by conditionally render our login and logout link. We will use a ternary statement so if the user contains data display the user image and logout else display login.

const { user } = this.props;

Our render method.

render() {console.log(this.props.user);return (<div className='nav container'><div className='desktop-nav'>{/* Make sure every link uses linkFunc, except the login link. s*/}<p className="nav-link" onClick={() => this.linkFunc('/')}>Home</p><p className="nav-link" onClick={() => this.linkFunc('/about')}>About</p><p className="nav-link" onClick={() => this.linkFunc('/cart')}>Cart</p>{/* Conditionally render the login button based if the user has data(it's login) else logout */}{/* Conditional render the user image if logged in. */}<div className="nav-link" onClick={() => this.props.user ? this.logout() : this.login()} >{this.props.user ? <div> <p>Logout</p> <img className='user-image' src={this.props.user.profile_picture} alt={this.props.user.nickname} /> </div> : <p>Login</p>} </div> </div> </div> );}

Also we updated our styles in our Nav.css.

.nav.container {display: flex;height: 20%;width: 100%;}.desktop-nav {position: fixed;background: cyan;width: 100%;color: #fff;display: grid;grid-template-columns: 15% 15% 15% 15% 15% 15%;}.nav-link {height: 100%;font-size: 2em;color: #fff;}.nav-link:first-child {grid-column: 3/3;}.nav-link:nth-child(2) {grid-column: 4/4;}.nav-link:nth-child(3) {grid-column: 5/5;}.nav-link:nth-child(4) {grid-column: 6/6;font-size: 1.5em;display: flex;justify-content: space-between;align-items: center;}.nav-link:nth-child(4) > div {height: 100%;width: 100%;display: flex;justify-content: space-between;align-items: center;}.user-image {height: 75%;padding: 5%;width: 30%;border-radius: 50%;}

That’s it now it should our user image and the logout link when they login.

Great Now we will setup cloudinary and setup our admin, so the admin can create products.

Here is my redux for reference:

Happy Coding!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store