Using JWT in Your React+Redux App for Authorization

Using JWT in Your React+Redux App for Authorization

An explanation and guide for how to handle JWT and Authentication in the frontend of your web app

The general idea is that you will save the current user’s information to the Redux store for easy access across your app. You will also save the JWT (JSON Web Token) associated with the user to localStorage so that their login can persist between sessions unless they explicitly logout.

This tutorial assumes you have the three following Rails API routes set up:

POST to /users > POST to /users > POST to /users 
These three routes handle the three essential parts of authentication — when a user creates an account, when a user logs into that account, and when a logged-in user revisits your web app. I will go in that order, although the final part (handling when a user revisits your app) is where JWT’s usefulness shines.

Let’s get started!

POST to /users > POST to /users ### 1. User Signs Up (POST to /users)

When a new user visits your app, you may want them to sign up for an account. You will essentially run a standard POST request; you won’t have to do anything fancy to get this up and running.

If set up properly, your backend will create the user instance, salt the password using BCrypt, and then return an object with a user key and a jwt key. This object is the important part to Auth. You’ll see it later in this tutorial, but we will essentially take the user object and save it to your Redux store, then take the token associated with the user and save it to localStorage.

The steps for signing up new users and automatically logging them in are as follows.

Have a New User Submission Form

In your React App, you’ll want a form which, upon submission, will run your fetch in your actions.js file. You will be making use of Redux’s thunk here, so make sure you have it installed.

Create a controlled component that is a form for creating a new user. As an example, it may look like this:

import React, {Component} from 'react';
import {connect} from 'react-redux';
import {userPostFetch} from '../redux/actions';

class Signup extends Component {
  state = {
    username: "",
    password: "",
    avatar: "",
    bio: ""
  }

  handleChange = event => {
    this.setState({
      [event.target.name]: event.target.value
    });
  }

  handleSubmit = event => {
    event.preventDefault()
    this.props.userPostFetch(this.state)
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <h1>Sign Up For An Account</h1>

        <label>Username</label>
        <input
          name='username'
          placeholder='Username'
          value={this.state.username}
          onChange={this.handleChange}
          /><br/>

        <label>Password</label>
        <input
          type='password'
          name='password'
          placeholder='Password'
          value={this.state.password}
          onChange={this.handleChange}
          /><br/>

        <label>Avatar</label>
          <input
            name='avatar'
            placeholder='Avatar (URL)'
            value={this.state.avatar}
            onChange={this.handleChange}
            /><br/>

          <label>Bio</label>
          <textarea
            name='bio'
            placeholder='Bio'
            value={this.state.bio}
            onChange={this.handleChange}
            /><br/>

        <input type='submit'/>
      </form>
    )
  }
}

const mapDispatchToProps = dispatch => ({
  userPostFetch: userInfo => dispatch(userPostFetch(userInfo))
})

export default connect(null, mapDispatchToProps)(Signup);

Your component does not have to look exactly like this — the important part is the handleSubmit function.

Note where some unknown function named userPostFetch is being imported from actions.js and then added as a prop to the component using mapDispatchToProps. You can see above that this prop is invoked upon submission of the form. This will be the function that handles the fetch itself, as well as saving the user object to the Redux store and adding the token to localStorage. Next, we will write this function.

Have a function with the fetch request

In your actions.js file, it will look something like this:

export const userPostFetch = user => {
  return dispatch => {
    return fetch("http://localhost:3000/api/v1/users", {
      method: "POST",
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
      },
      body: JSON.stringify({user})
    })
      .then(resp => resp.json())
      .then(data => {
        if (data.message) {
          // Here you should have logic to handle invalid creation of a user.
          // This assumes your Rails API will return a JSON object with a key of
          // 'message' if there is an error with creating the user, i.e. invalid username
        } else {
          localStorage.setItem("token", data.jwt)
          dispatch(loginUser(data.user))
        }
      })
  }
}

const loginUser = userObj => ({
    type: 'LOGIN_USER',
    payload: userObj
})

Note the two separate functions: userPostFetch and loginUser. The function userPostFetch sends the user’s info to your backend to be verified. Upon success, it is expecting a response of a JSON object that looks like this:

{
  user: {
    username: "ImANewUser",
    avatar: "https://robohash.org/imanewuser.png",
    bio: "A new user to the app."
  },
  jwt: "aaaaaaa.bbbbbbbb.ccccccc"
}

In userPostFetch, this is what we named ‘data’ in the 2nd ‘then’ statement.

Save the token to localStorage

With the code we’ve written in our userPostFetch function, localStorage.setItem(“token”, data.jwt) will save the token (“aaaaaaa.bbbbbbbb.ccccccc”) to our user’s localStorage. This will be used later when we are persisting a user’s login between sessions.

To check that the token was saved successfully, run localStorage.token or localStorage.getItem(“token”) in your console.

Save user object to your Redux store

As for the user object, we see here that dispatch(loginUser(data.user)) is being ran. Presumably, your reducer will take the user object ({username: “ImANewUser”}) and save it to your Redux store. This will make it easy for any component in your React App to know who the current user is.

As an example, here is my reducer:

const initialState = {
  currentUser: {}
}

export default function reducer(state = initialState, action) {
    switch (action.type) {
      case 'LOGIN_USER':
        return {...state, currentUser: action.payload}
      default:
        return state;
    }
}

Here, the user object (action.payload) is being saved to the state under the key of currentUser. If you have Redux DevTools installed, you can check it after the successful creation of your user. You should see the user object.

You may notice here that I have a key of “reducer” that you might not have. This is because I have multiple reducers and named one of them “reducer”.

POST to /users > POST to /users 
That’s it for signing up a new user. Next, we’ll check out how to log in an existing user.

2. User Logs In (POST to /login)

Logging in a user is very similar to the signup process, except you are sending only the login credentials to the backend. The backend will handle validating the user and then sending back the same object from sign up — an object with a user key and jwt key. Once again, you’ll save the user object to the Redux store and save the token to localStorage.

If you have a component dedicated to logging in, it will look similar to your Signup component with one major difference — it will be importing a different function from your actions.js file. It might look something like this:

import React, {Component} from 'react';
import {connect} from 'react-redux';
import {userLoginFetch} from '../redux/actions';

class Login extends Component {
  state = {
    username: "",
    password: ""
  }

  handleChange = event => {
    this.setState({
      [event.target.name]: event.target.value
    });
  }

  handleSubmit = event => {
    event.preventDefault()
    this.props.userLoginFetch(this.state)
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <h1>Login</h1>

        <label>Username</label>
        <input
          name='username'
          placeholder='Username'
          value={this.state.username}
          onChange={this.handleChange}
          /><br/>

        <label>Password</label>
        <input
          type='password'
          name='password'
          placeholder='Password'
          value={this.state.password}
          onChange={this.handleChange}
          /><br/>

        <input type='submit'/>
      </form>
    )
  }
}

const mapDispatchToProps = dispatch => ({
  userLoginFetch: userInfo => dispatch(userLoginFetch(userInfo))
})

export default connect(null, mapDispatchToProps)(Login);

Note that the only thing that changed about the form itself was the removal of the avatar and bio input fields.

We haven’t yet written the userLoginFetch function, but again, its appearance is similar to the fetch that handled sign up. See below:

export const userLoginFetch = user => {
  return dispatch => {
    return fetch("http://localhost:3000/api/v1/login", {
      method: "POST",
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
      },
      body: JSON.stringify({user})
    })
      .then(resp => resp.json())
      .then(data => {
        if (data.message) {
          // Here you should have logic to handle invalid login credentials.
          // This assumes your Rails API will return a JSON object with a key of
          // 'message' if there is an error
        } else {
          localStorage.setItem("token", data.jwt)
          dispatch(loginUser(data.user))
        }
      })
  }
}

Note here that we are reusing the loginUser action in order to save our user object to our state.

Surprisingly, that’s it for logging a user in! When a user’s object is saved to the state and their token is saved to localStorage, you can consider your user logged in.

Now let’s do the third and final part: persisting your user’s login between sessions.

3. User Revisits (GET to /profile)

The point of saving a token to localStorage is to persist a login. When your user revisits your site, you want them to feel as if they are continuing their session from before.

Remember though that the token saved into localStorage is just a string. It in itself does not equal a logged-in user. You as the developer must take the token and translate it into a persisting login.

To do this, you will want to run your fetch (GET to /profile) every time your app is accessed if the user has a token saved into their localStorage. Running this logic in componentDidMount in your App component is a good choice, as it will definitely run when your app is accessed.

import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import {connect} from 'react-redux';
import {getProfileFetch} from './redux/actions';
import Signup from './components/Signup';
import Login from './components/Login';


class App extends Component {
  componentDidMount = () => {
    this.props.getProfileFetch()
  }

  render() {
    return (
      <div>
        <Switch>
          <Route path="/signup" component={Signup}/>
          <Route path="/login" component={Login}/>
        </Switch>
      </div>
    );
  }
}

const mapDispatchToProps = dispatch => ({
  getProfileFetch: () => dispatch(getProfileFetch())
})

export default connect(null, mapDispatchToProps)(App);

Your App component won’t look exactly like this (you can especially ignore the Switch and Routes parts), but the key part here is the getProfileFetch function being given as a prop to App and then invoked in componentDidMount.

We’re importing a function from actions.js called getProfileFetch, which is ran immediately when the App component mounts.

What getProfileFetch will do is run a standard GET request, except with an Authorization header with the token, which you handle in your actions.js file. Your backend should be set up to receive the token, decode it, and then return its associated user object. You then save this to the Redux store as usual. You already have the token saved to localStorage, so you don’t have to worry about it.

The function will look something like this:

export const getProfileFetch = () => {
  return dispatch => {
    const token = localStorage.token;
    if (token) {
      return fetch("http://localhost:3000/api/v1/profile", {
        method: "GET",
        headers: {
          'Content-Type': 'application/json',
          Accept: 'application/json',
          'Authorization': `Bearer ${token}`
        }
      })
        .then(resp => resp.json())
        .then(data => {
          if (data.message) {
            // An error will occur if the token is invalid.
            // If this happens, you may want to remove the invalid token.
            localStorage.removeItem("token")
          } else {
            dispatch(loginUser(data.user))
          }
        })
    }
  }
}

The function getProfileFetch first checks if there is a token saved into localStorage before attempting to persist a login. This way, you won’t run an unnecessary fetch.

Note here again that we are reusing the loginUser action and that we are not re-saving the token. The user already has it in their localStorage, so there’s no need to save it again.

And there you have it — you have functioning authorization!

*** BONUS: Logging Out

As you test your app, you’ll notice that currently the only way to log out is to clear the JWT token in your localStorage by typing localStorage.removeItem(“token”) into your console and pressing refresh to clear the Redux store. We should create a button for your clients to log themselves out.

Somewhere in your app, you’ll need a logout button which will do the above. While I wouldn’t place this randomly in the App.js file, here is an example of a logout button in App.js for sake of example.

import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import {connect} from 'react-redux';
import {getProfileFetch, logoutUser} from './redux/actions';
import Signup from './components/Signup';
import Login from './components/Login';


class App extends Component {
  componentDidMount = () => {
    this.props.getProfileFetch()
  }

  handleClick = event => {
    event.preventDefault()
    // Remove the token from localStorage
    localStorage.removeItem("token")
    // Remove the user object from the Redux store
    this.props.logoutUser()
  }

  render() {
    return (
      <div>
        <Switch>
          <Route path="/signup" component={Signup}/>
          <Route path="/login" component={Login}/>
        </Switch>
          {this.props.currentUser.username
            ? <button onClick={this.handleClick}>Log Out</button>
            : null
          }
      </div>
    );
  }
}

const mapStateToProps = state => ({
  currentUser: state.reducer.currentUser
})

const mapDispatchToProps = dispatch => ({
  getProfileFetch: () => dispatch(getProfileFetch()),
  logoutUser: () => dispatch(logoutUser())
})

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

You should notice a few new things: for one, there is a new action being imported called logoutUser, which we will write shortly. We also now have mapStateToProps being used in order for the App component to receive a prop called currentUser.

POST to /users 
There is now also a ternary operator which checks if the currentUser prop received from the Redux store has a username key (as in, if the currentUser object is empty or not). If it does, it renders a ‘Log Out’ button, which will invoke logoutUser when clicked. It will also remove the token from localStorage.

logoutUser will just be a simple action:

export const logoutUser = () => ({
  type: 'LOGOUT_USER'
})

This action will do the following in the reducer, replacing the currentUser with an empty object:

const initialState = {
  currentUser: {}
}

export default function reducer(state = initialState, action) {
    switch (action.type) {
      case 'LOGIN_USER':
        return {...state, currentUser: action.payload}
      case 'LOGOUT_USER':
        return {...state, currentUser: {} }
      default:
        return state;
    }
}

And there you have it! You should see the button appearing and disappearing when you log in and log out.

How to Check?

You may have followed the above and are questioning if your authorization is working. You can test it by signing up, logging in, pressing refresh, and logging out. If everything works as it should, you should see the user object saved to your Redux store under the key of currentUser using your Redux DevTools and a token saved to your localStorage which you can view in the console.

Now What?

As for where to go from here, you can run checks in your components to essentially kick a user out if they are not logged in. You can do this with Redirect from react-router-dom or the push function from connected-react-router. These are the resources I prefer to use.

You can also now pass your currentUser object from your Redux store to any component in your app, as we saw earlier. For example, if you wanted your Navbar to show the user’s avatar, you could use mapStateToProps to pass the currentUser object to the Navbar and then render the avatar.

Thanks for reading ❤

If you liked this post, share it with all of your programming buddies!

Should I choose Redux or Flux for ReactJS?

Having a similar state, action and unidirectional data flow, the Flux and Redux do have some differences.

An intro to Redux and how state is updated in a Redux application

An intro to Redux and how state is updated in a Redux application

I started learning Redux a few days back and it was an overwhelming concept for me at the start. After polishing my skills in ReactJS by making a&nbsp;<a href="https://github.com/aimenbatool/my-reads" target="_blank">personal book reading application</a>, I headed towards Redux to learn more about it.

I started learning Redux a few days back and it was an overwhelming concept for me at the start. After polishing my skills in ReactJS by making a personal book reading application, I headed towards Redux to learn more about it.

Today, I’m going to share a few core Redux concepts without using any view library (React or Angular). This is a kind of a personal note for future reference but it can help others as well.

Let’s dig in together!

What is Redux?

Redux is an open-source library to improve the predictability of the state in a JavaScript application. It is an independent library. It is commonly used with other libraries like React and Angular for better state management of the application. Redux was created by Dan Abramov in 2015 to handle complex state management in an efficient way.


When an application grows larger it becomes harder to manage the state and debug for issues. It becomes a challenge to track when and where the state is changed and where the changes need to be reflected. Sometimes a user input triggers some API call which updates some model. That model in turn updates some state or maybe the other model and so on.

In such a situation it becomes grinding to track the state changes. It happens mainly because there is no defined rule to update a state and state can be changed from anywhere inside the application.

Redux tries to solve this issue by providing a few simple rules to update the state to keep it predictable. Those rules are the building blocks of Redux.

Redux Store:

As we discussed earlier, the main purpose of Redux is to provide predictable state management in our applications. Redux achieves this by having a single source of truth, that is a single state tree. The state tree is a simple JavaScript object which holds the whole state of our application. There are only a few ways to interact with the state. And this makes it easy for us to debug or track our state.


We now have only one main state which occupies the whole state of the application located at a single location. Any changes made into the state tree are reflected in the whole application because this is the only source of data for the app. And, this is the first fundamental principle of Redux.

Rule #1 — Single source of truth

The state of your whole application is stored in an object tree within a single store. — Official docs

The ways you can interact with a state tree are:

  • Getting the state
  • Listening to the changes in the state
  • Updating the state

store is a single unit that holds the state tree and the methods to interact with the state tree. There is no other way to interact with a state inside the store except through these given methods.

Let’s talk about the methods a store gives us to interact with the state.

  • getState() — Returns the current state of the application.
  • dispatch(action) — The only way to update a state is by dispatching an action and dispatch(action) serves the purpose. We will talk more in detail in a bit.
  • subscribe(listener) — The purpose of this method is to listen for the state changes. Every time a state is changed, it will be called and will return the updated state.
  • replaceReducer(nextReducer) — Replaces the reducer currently used by the store to calculate the state.

Now when we have a store which contains a state tree and a few ways to interact with the state, how can we update application state?

Updating state in the application:

The only way to update a state is to dispatch an action. This is the 2nd rule.


Rule #2 — State is read-only

An action is a plain JavaScript object to keep track of the specific event taking place in the application. What makes it special is a ‘type’ property which is a necessary part of it.


{
  type: "ADD_BOOK_TO_THE_CART"
}

The main purpose of this property is to let Redux know about the event taking place. This type should be descriptive about the action. Along with the ‘type’ property, it can have other information about the event taking place.

Actions can have as much information as you want. It is a good practice to provide less and necessary information — preferably an id or any unique identifier wherever possible.

Here we have an action to add a book to the cart.

{
    type: 'ADD_BOOK_TO_THE_CART',
    bookId: 10, 
}

Once we define our action we pass it to the dispatcher. store.dispatch() is a function provided by the library which accepts an action to perform an action against the state. Redux restricts updating the state to this method only.

store.dispatch({
    type: 'ADD_BOOK_TO_THE_CART',
    bookId: 10,
})

This strict way of updating the state ensures that the state can not be changed directly either by view or any network callback. The only way to update a state is by defining the action and then dispatching it. Remember that actions are plain JavaScript objects. Actions can be logged, serialized, and replayed for debugging purposes.

We now have a store, a state, and an action in our app to perform some tasks against the state. Now we need a way to use these actions to actually do the update. This can be done by using a pure function and this is rule #3.

Rule#3 — Changes are made with pure functions

Magic happens here. We need a simple pure function, which, as a parameter, takes the current state of the application and an action to perform on the state, and then returns the updated state. These functions are called reducers.

function booksReducer (state = [], action) {
// Magic is happening here...
  }

These are called reducers because they take the collection of values, reduce it to an updated state and then return it. Since reducers are pure functions they do not mutate the original state. Instead, they return the updated state in a new object. Our application can have one or more than one reducer. Each reducer can have a relevant state to perform specific tasks.

function booksReducer (state = [], action) {
    switch(action.type) {
        case ADD_BOOK_TO_THE_CART:
            return state.concat([action.bookId]);
        case REMOVE_BOOK_FROM_CART:
            return state.filter( book => book.bookId !== action.bookId);
        // a few more actions
        default:
            return state;
    } 
}

Since reducers are pure functions, they should have the following attributes:

  • Given the same input, it should return the same output every time — No mutation is allowed.
  • No side effects — No API call data change from an external source.

The process.

If we connect the dots, Redux is a library which has a store that contains a state tree and a few methods to interact with the state. The only way to update a state inside a store is to dispatch an action and define a reducer function to perform tasks based on the given actions. Once dispatched, the action goes inside the reducer functions which performs the tasks and return the updated state to the store. This is what Redux is all about.

State update flow in Redux

What have we learned so far?

Let’s summarize what we have learned so far to connect the dots.


  • Redux — An opensource predictable state container
  • State Tree — A plain JavaScript object which contains whole application state
  • Three ways to interact with a state (the only ways):
  • Store — A single unit which contains state tree & methods to interact with the state tree
  • Actions — Plan Javascript objects to describe the action taking place
  • Reducers — Pure Javascript functions to take current state and an action to return a new state

Since Redux is an independent library which can be used with React, Angular or any other library, I avoided making a sample application with any of these view libraries. Instead, I focused on the core Redux concepts only.

Redux can be overwhelming at first and if you are a newbie or junior developer it can give you a tough time. But consistency and a positive attitude is the key to success.

Originally published on https://medium.freecodecamp.org



Redux in React

Redux in React

React Redux is maintained by the Redux team, and kept up-to-date with the latest APIs from Redux and React.

React Redux is maintained by the Redux team, and kept up-to-date with the latest APIs from Redux and React.

React is all about moving parts that pass information to each other. You will notice sometimes you have really long chains that go through several containers and several components. This can be a hassle if the data got messed up in one of the steps and you have to slowly backtrack and look through each part to find the error. there is where Redux comes into play! Redux stores all of your state information in a separate object, and any component can get the information it needs from this object. So instead of going home => container1 => component1=> component2, it will go home => Redux Object => component2. Lets see how this all works!

First is the reducer function.

You have two objects that are separate from everything else, the state and the action. The state contains, well, the state of your page, and the action contains the instructions to update that state.

let state = {name: "abc"}
let action = {type: "JOE-IFY"}

To allow action to modify state, you need a function.

function changeState(state, action) {
   if (action.type === 'JOE-IFY') {
      return {name: 'Joe'}
   }
}

If the action type is ‘JOE-IFY’, change the state of name to be “Joe”. There can be many different commands to change names, typically a switch case it used. However, to make sure a null or undefined is never returned a default case is added that returns the previous state.

function changeState(state, action) {
   switch (action.type) {
      case 'JOE-IFY':
         return {name: 'Joe'}
      default: 
         return: state
   }
}

Now if you ran the changeState function with the state and “JOE-IFY” you would get {name: “Joe”}.

If you had another action type, for example to change the name to “Bob” it would look like:

function changeState(state, action) {
   switch (action.type) {
      case 'JOE-IFY':
         return {name: 'Joe'}
      case 'BOB-IFY':
         return {name: 'Bob'}
      default: 
         return: state
   }
}

Now if you instead ran it with the function “BOB-IFY” you would get {name: “Bob”}. This changeState function is called the “reducer”, as it reduces the state and action into a new state.

You can make it more complicated as well, since an action can have multiple attributes.

let state = {name: "abc"}
let action = {type: "CHANGE_NAME",
              newName: "Spooderman"}

You will have to change the function such that it changes the state of name to that of newName. Something like:

function changeState(state, action) {
   switch (action.type) {
      case 'CHANGE_NAME':
         return {name: action.newName}
      default: 
         return: state
   }
}

This is the gist of how a reducer function works.

Using Redux in a React App

First install redux.

npm install redux

Install react-redux.

npm install react-redux

Inside your “src” folder, create a “reducers” folder, and inside the “reducers” folder create a “reducerFunctionName.js” file.

Redux gives you the createStore() function, which when called returns the state. React-redux gives you the “provider” component, where store is passed in and is subsequently passed down everywhere else. React-redux also lets us re-render whenever the specified changes to the state happen via the connect method. Import them both into index.js. Also import your reducer function.

import {createStore} from 'redux';
import {Provider} from 'react-redux'
import reducerFunctionName from './reducers/reducerFunctionName.js'
const store = createStore(reducerFunctionName);
ReactDom.render(
   <Provider store={store}>
      {' '}
      <App />
   </Provider>, 
   document.getElementById('root')
)

Now we can pass the store and access it in every component. To any component that wishes to access the store, import connect from react-redux and modify the export.

import {connect} from 'react-redux'
const mapStateToProps = state => {
   return {
      name: state.name
   }
}
const mapDispatchToProps = state => {
   return {
      changeName: () => dispatch({type: "CHANGE_NAME"})
   }
}
export default connect(
   mapStateToProps,
   mapDispatchToProps
)(App);

mapDispatchToProps allows us to have access to the “changeName” function, which is what we are calling us passing in action.type “CHANGE_NAME” to the reducer. Similarly, name is provided by the mapStateToProps function, which gives us access to the name in the state.

Your components now have access to the state information inside the store object, and are able to access the functions needed to change the state. Just about done!

One final thing. Now what if you had multiple functions? You can theoretically transform all of them into different cases for the same reducer function, but this would be weird; you would have a case for “CHANGE_NAME”, a case for “BUY_FOOD”, and other cases for tons of weird things that have nothing to do with each other. It is better to separate out the reducer functions. This can be done through “combineReducers”.

In the “reducers” folder create a new file called “rootReducer.js”. At the top enter:

import {combineReducers} from 'redux'

Then copy paste your other reducer functions over, but without the export default part in front of them. Then add it to the end.

export default combinedReducers({
   nameChanger,
   colorChanger
})

Note that now to access information from on of the reducers you have to specify the reducer name first now, so instead of “state.name” if name is stored in the nameChanger function you need to do “state.nameChanger.name”.

Go back to your index.js and import rootReducer from “./reducers/rootReducer.js”, you don’t need the earlier individual file imports anymore.

Your finished combinedReducer should look something like this:

import {combineReducers} from 'redux'
function colorChanger(state = {color: "red"}, action) {
  switch (action.type) {
    case 'CHANGE_COLOR':
      console.log(state);
      return {color: action.newColor}
    default:
      return state;
  }
}
function nameChanger(state = {name: "zed"}, action) {
  switch (action.type) {
    case 'CHANGE_NAME':
      console.log(state);
      return {name: action.newName}
    default:
      return state;
  }
}
export default combineReducers({
  nameChanger,
  colorChanger
})

And an example app.js that uses the above reducers might look something like:

import './App.css';
import React, {Component} from 'react';
import {connect} from 'react-redux';
import Something from './containers/Something.js'
class App extends Component {
handleChange = (event) => {
    this.props.changeName(event.target.value)
  }
handleChange2 = (event) => {
    this.props.changeColor(event.target.value)
  }
render () {
    return (
      <div className="App">
        <form>
          <label>
          NewName: <input type="text" onChange={event => {this.handleChange(event)}}/>
          <br/>
          NewColor: <input type="text" onChange={event => {this.handleChange2(event)}}/>
          </label>
          <br/>
          <input type="submit"/>
        </form>
        <p>{this.props.name}</p>
        <p>{this.props.color}</p>
      </div>
    )
  }
}
const mapStateToProps = state => {
  return {
    name: state.nameChanger.name,
    color: state.colorChanger.color
  };
}
const mapDispatchToProps = dispatch => {
  return {
    changeName: (event) => dispatch({type: 'CHANGE_NAME', newName: event }),
    changeColor: (event) => dispatch({type: 'CHANGE_COLOR', newColor: event })
  };
}
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);

The default states for name and color are shown at the bottom. The redux state for name and color can be updated through the input bars, and the updated state is shown again with the new name and color.

And we are all done! That was a long ride and took me quite a while to figure out, so hopefully this guide helps you learn Redux faster than I did! Happy coding with your newfound knowledge of Redux!