DEV Community

NJOKU SAMSON EBERE
NJOKU SAMSON EBERE

Posted on

REDUX in broken pieces - NO REACT

It is comfortable to say that many developers only heard of or learnt about REDUX because of REACT.

JUMP TO

  1. Pieces of REDUX
  2. Pictorial Illustration
  3. Final Code
  4. Improving our code
  5. Conclusion

However, Redux is a state management library created independent of React. This means that these two libraries do not need each other to function.

This tutorial is meant to help beginners see that REDUX is not as complex as it might seem to be when working with REACT. We will be discussing only REDUX - NO REACT. By the end, you should have a clear picture of how REDUX work with or without REACT

Pieces of REDUX

Actions
Reducer
Store
subscribe

Actions (Input)

An action is a command received from the application UI. This command determines how the state is to be manipulated. A typical action is made up of a TYPE (i.e. A unique identifier of an action. It is usually a string e.g "ADD", "SUB" etc.) and a PAYLOAD (i.e. A value that will be used to manipulate the state)

The code will look like this:


store.dispatch({
  type: "ADD",
  payload: 10,
});

store.dispatch({
  type: "SUB",
  payload: 50,
});

Enter fullscreen mode Exit fullscreen mode

Reducer (Processor)

The reducer is a function that manipulates the state of the application depending on the action that is sent (dispatched) from the application UI.

A reducer code will look like this:

const reducer = (state, action) => {
  switch (action.type) {
    case "ADD":
      state = state + action.payload;
      break;

    case "SUB":
      state = state - action.payload;
      break;
  }

  return state;
};
Enter fullscreen mode Exit fullscreen mode

From the code, it receives 2 parameters (i.e. the application initial state and the action dispatched or sent from the application UI).

Next, a conditional statement (switch...case...) is used to determine if the action received exists and then, the corresponding code of the action is executed. Each case represents an action (ADD, SUB).

Finally, the new state is returned after manipulation. It will return the initial state if nothing happened.

Store (Memory)

The store is the global house for the data (state) of the application. This is where you can set the initial state (if you choose to do so) which will be absorbed into the reducer's state by default.

The code will look like this:

const store = createStore(reducer, 1);
Enter fullscreen mode Exit fullscreen mode

The first argument there is the reducer (obviously) while the second parameter there is the initial state

Subscribe (Output)

The subscribe function is used to return the output (New State) after the reducer has finished processing the data.

The code will look like this:

store.subscribe(() => {
  console.log("state changed" + " " + store.getState());
});
Enter fullscreen mode Exit fullscreen mode

The most important part of the subscribe code is store.getState(). That is what gives the output from the store.

Pictorial Illustration

UI => ACTIONS => REDUCERS => STORE => UI

Alt Text

Putting the pieces together

Let me now walk you through the process of creating a basic redux application

  • Create a folder or directory named redux
mkdir redux-basics
Enter fullscreen mode Exit fullscreen mode
  • Navigate into the directory
cd redux-basics
Enter fullscreen mode Exit fullscreen mode
  • Initialize the project
npm init
Enter fullscreen mode Exit fullscreen mode
  • Install redux
npm install redux
Enter fullscreen mode Exit fullscreen mode
  • Create a file named index.js
// for Mac
touch index.js

// for windows
echo .>index.js
Enter fullscreen mode Exit fullscreen mode
  • In the file, require redux like so
const { createStore } = require("redux");
Enter fullscreen mode Exit fullscreen mode
  • Next, Create the following actions
store.dispatch({
  type: "ADD",
  payload: 10,
});

store.dispatch({
  type: "SUB",
  payload: 50,
});

Enter fullscreen mode Exit fullscreen mode
  • Create the following reducer just above the actions

const reducer = (state, action) => {
  switch (action.type) {
    case "ADD":
      state = state + action.payload;
      break;

    case "SUB":
      state = state - action.payload;
      break;
  }

  return state;
};

Enter fullscreen mode Exit fullscreen mode
  • Next create the store below the reducer
const store = createStore(reducer, 1);
Enter fullscreen mode Exit fullscreen mode
  • Finally, create the subscribe function below the store. This will output the new state each time the reducer is done processing
store.subscribe(() => {
  console.log("state changed" + " " + store.getState());
});
Enter fullscreen mode Exit fullscreen mode

Final Code


const { createStore } = require("redux");

const reducer = (state, action) => {
  switch (action.type) {
    case "ADD":
      state = state + action.payload;
      break;

    case "SUB":
      state = state - action.payload;
      break;
  }

  return state;
};

const store = createStore(reducer, 1);

store.subscribe(() => {
  console.log("state changed" + " " + store.getState());
});

store.dispatch({
  type: "ADD",
  payload: 10,
});

store.dispatch({
  type: "SUB",
  payload: 50,
});

Enter fullscreen mode Exit fullscreen mode

To test the code, go back to your terminal and run the following command

node index
Enter fullscreen mode Exit fullscreen mode

This is my output:
Alt Text

Notice that from the output, the first new state was 11 after adding the payload 10 to the initial state 1. The new state is updated to -39 after subtracting the payload 50 from the current state 11.

In summary, this is what happened

state = state (i.e. 1) + payload (i.e. 10)
      = 1 + 10
      = 11

state = state (i.e. 11) - payload (i.e. 50)
      = 11 - 50
      = -39 
Enter fullscreen mode Exit fullscreen mode

Improving our code

You must have noticed that we have been manipulating our state directly. This is bad practice and could cause disaster in the future.

You will also have noticed how the initial state is passed straight into the store

Let's clean up all that and make our code a little more future-proof in the next REDUX code


const { createStore } = require('redux');

// initialize the state here
const initialState = {
    age: 21
};

// create the reducer here
const myReducer = (state = initialState, action) => {
    const newState = {...state};

    // define the action here
    // for ADD
    if(action.type === 'ADD'){
        newState.age += action.val;
    }

    // for SUB
    if(action.type === 'SUB'){
        newState.age -= action.val;
    }
    return newState;
};

// create store here
const store = createStore(myReducer);

store.subscribe(() => {
    // log output here
    console.log('state changed' + JSON.stringify(store.getState()));
})

//set actions here
store.dispatch({type:'ADD', val: 10});
store.dispatch({type:'SUB', val: 5});

Enter fullscreen mode Exit fullscreen mode

As a REDUX expert, I know these are self explanatory to you. The most important changes here are

  1. We now have a stand-alone initial state

  2. The initial state is assigned to the reducer's state

  3. We are creating and manipulating a copy of the state instead of the main state. This keeps our state intact.

This is the output:
Alt Text

Conclusion

There are 4 major part of a REDUX application namely: action, reducer, store and subscribe.

Every other redux code are based on the fundamental parts. So even if you are working with react, always have this redux picture in mind and you will not find it so difficult.

All Codes are here

GitHub logo EBEREGIT / Redux-basics

understanding the basics of redux without any external packages

Thank you for reading!!!

Top comments (0)