مدونات

Getting started with Redux. What is Redux?

04

19 نوفمبر

Ahmed Alaa

8 min read.

Why we should use Redux?

Managing the state can get very difficult as our application grows, this is the problem that we can handle it using Redux, Redux has its own global state so all page or components if you are using a JavaScript library like react can see this state and use it anywhere.

What is Redux?

Standalone third party library, that used to make the state management easier.

What is State?

an object that makes your app dynamic and more interactive, example: if you are using authentication, and you want to know if the user is authenticated or not, state can handle that and determine which options of the menu we want to show to the authenticated user.

Redux Flow

Let’s see how Redux mange data and how it updates states Using Store, Actions and Reducers: 

 

It’s all about a central store that store the entire application state, you can think about it as a giant JavaScript object.

 

The first building block besides the central store are actions which are dispatched from your JavaScript code. That action doesn’t directly reach the store it doesn’t hold any logic, it doesn’t know how to update the store, it’s just a messenger.

 

The thing changing the store is the reducer. Now here I’ve written reducers because we actually can combine multiple reducers into one, but in the end, you’ll end up with one reducer which is directly connected to your store in the end so that the action reaches the reducer. And since the action contains a type, the reducer can check the type of the action.

 

  • So, this is the reducer, it spits up the updated state stored in the store and replaces the old state. So we always return a new state, because we want to make sure that we don’t accidentally change the old one. So, that is how the reducer handles the action, now the store is up to date.
  • The last thing is a subscribe method, it is a function which will be called any time an action is dispatched, and some parts of the state tree may potentially have changed. Let’s see it in our code.

Installation

Let’s dive into some code: Make sure that you have installed node.js & npm packages.

  • create a Redux-basics folder and run this command at your command line.

npm init

  • Now we want to install node modules using this command

npm install

  • Beside your package.json file, create Redux-basics.js file and open it using your code editor.
  • Now let’s install Redux

npm install –save redux

  • Now at this Redux file i want to create everything that i need to use Redux.

// Store

// Reducers

// Dispatching Actions

// Subscription

  • Let’s start with the store and for that i want to import something from Redux using node syntax.

const redux = require(‘redux’);

// Reducers

// Dispatching Actions

// Subscription

  • So, here create a constant createStore which refers to Redux.createStore.

const createStore = redux.createStore;

  • createStore is a function that allows us to create a new Redux store, I will store it at a constant named store and simply execute it.

const store = createStore();

  • A store needs to be initialized with a reducer, and remember we only have one reducer. So, we need to pass the reducer to this creation function. Let’s create our reducer before our store.

const redux = require(‘redux’);

const createStore = redux.createStore ;

// Reducer

const rootReducer = () => {}

// Store

const store = createStore() ;

  • The reducer function receives two arguments: The state and the action and the state is the old state which will get updated, then the function should return the updated state but for now, we will just return the old state.

// Reducer

const rootReducer = (state , action) => {

     return state;

}

// Store

const store = createStore();

  • We can already use our reducer and pass it as an argument to the store, Now we have a created store that hold undefined state.

// Store

const store = createStore(rootReducer);

  • We can verify this by console logging the state using getState, which it is a function that pull out the state from the store.

// Store

const store = createStore(rootReducer);

console.log(store.getState());

  • Then execute the file with nodeJS using command node + filename , This will execute the file and show any console log output, and now you see undefined, The state is undefined because we are returning the old state, and we never initialize a value to our state.

$ node redux-basics.js

// undefined

  • Let’s initialize our state and name our constant intialState, It could be a js object or a number it could be anything we want, here we will initialize it with an object that hold a counter with a value of zero.

const intialState = {

     counter : 0

}

  • At my rootReducer, i will use a feature provided by ES6, i can initialize the argument of the function with a default value, and when we call our function the argument will take the default value instead.

const intialState = {

     counter : 0

}

// Reducer

const rootReducer = (state = intialState , action) => {

     return state;

}

// Store

const store = createStore(rootReducer);

console.log(store.getState());

  • Now i showed you how to create the store with a reducer, and how to initialize the state, Here is how our file should look like: 

const redux = require(‘redux’);

const createStore = redux.createStore ;

const intialState = {

     counter : 0

}

// Reducer

const rootReducer = (state = intialState , action) => {

     return state;

}

// Store

const store = createStore(rootReducer);

console.log(store.getState());

 

let’s jump to how we dispatch actions. Dispatch is a function and it takes an argument which is an action, and the action should be a JavaScript object that has a type property, this will later be important in building block in getting the information which type of action was dispatched and what we should do is the reducer that is why type is so important, The convention of type is to use all Uppercase string.

// Dispatch Actions

store.dispatch({ type : ‘INCREMENT_COUNTER });

  • Let’s make another action which adds a number to our counter, this value we will add needs to be passed along with the type property, remember the object that contains our type? We add to this object a value, name , ID whatever you want.

// Dispatch Actions

store.dispatch({ type : ‘INCREMENT_COUNTER });

store.dispatch({

     type : ‘ADD_VALUE’,

     payload : 10        // Increase our counter by 10

})

  • Now we are dispatching two actions. What do you think these actions do to our store? Let’s console log our state to see and think what did you expect to get now after executing our file ?

// Dispatch Actions

store.dispatch({ type : ‘INCREMENT_COUNTER’ });

store.dispatch({ type : ‘ADD_VALUE’,payload : 10 });

console.log( ‘State after dispatch action : ‘ , store.getState() );

  • After you execute the file, you see the output of the state still 0 but why ? why it did’t increment by one then added 10 to be 11? because we have created our actions but we didn’t listen for its types anywhere.

npm redux-basics.js

{ counter : 0 }

State after dispatch action { counter : 0 }

  • At our reducer let’s listen for our action types, and remember before we returned the old state but we said we should return the updated one so here is the tip, don’t mutating the original state, you should return a new js object which you copy the old state with spread operator then overwrite the property you want to adjust, here we it will be incremented counter.

// WE DON’T DO THIS

const rootReducer = (state = intialState , action) => {

     if( action.type === ‘INCREMENT_COUNTER’){

     state.counter++;

     return state;

}

}

// WE DO THIS

const rootReducer = (state = intialState , action) => {

     if( action.type === ‘INCREMENT_COUNTER’){

     return {

     …state,

     counter : state.counter+1

     }

     return state ;

}

  • Now state is updated to be 1 instead of 0 , We can add more if statement to listen for action that adding a value to our counter.
  1. at our reducer first, if statement we check for the action type then we increment.
  2. second reducer we also check for the action type then we add it to payload we have at our action.

const rootReducer = (state = intialState , action) => {

     if( action.type === ‘INCREMENT_COUNTER’){

       return {

       …state,

       counter : state.counter + 1

       }

     }

     if( action.type === ‘ADD_VALUE’){

       return {

       …state,

       counter : state.counter + action.payload 

       }

     }

     return state ;

  • Now, if run your file you will notice that our state is updated after dispatching our actions then we listened for them at our reducer.

$ node redux-basics.js

// output

State Before dispatching action: { counter: 0 }

State after dispatch action is : { counter: 11 }

The last thing here is the subscribe() which allows us to follow up on the state anytime it gets updated, it is a method which its argument is a function which called anytime an action is dispatched, and some part of the state tree may changed. Inside it use getState() to read the current state tree inside the callback.

  • Let’s code our subscription and use it after our store to get informed about any future dispatch.

// Store

const store = createStore(rootReducer);

console.log(store.getState());

store.subscribe( () => {

    console.log(‘Subscription’ , store.getState());

})

  • Here is the output

State Before dispatching action { counter: 0 }

Subscription { counter: 1 }

Subscription { counter: 11 }

State after dispatch action is : { counter: 11 }

  • Here is how your file should look like:

 

Summary

  1. What is Redux & how it work
  2. what is the store and how to create one
  3. what is reducers & we initialize it with the store
  4. what is action & how we dispatch them
  5. what is subscription
You can also check our series of articles about Redux:

That’s it!. I hope this helped you 🙂

تعليقات