Simple Redux Introduction in Vanilla Javascript
In this video you will learn what is the core idea of Redux on the plain javascript example.
Let's jump right into it.
So what is Redux. In official website it says that it's a state container for Javascript application. Which doesn't bring any clarity. To make it understandable it's a global object where the whole state of our application is written. And from any place we can get data from there or change some data.
So the main problem on frontend is that we have data through the whole application in different places. And it's difficult to maintain all this data and pass from one place to another. This is why the global big object with all data is really a solution to all problems.
So second problem is when we want to change all this data which exists in different parts of application. We call change in module 1 and module 1 calls change in module 2 then module 2 calls change in module 1 or 3 and it's really not supportable.
Very often you can hear that this is some additional thing for React. But actually it doesn't have anything to do with React.
Let's look on the example how we can use Redux in a plain html page with minimum Javascript.
So here I have a plain index.html and I just put here redux.js from cdn. So know we have Redux as a window element with some methods inside.
<!DOCTYPE html>
<html>
<head>
<title>This is the title of the webpage!</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.js"></script>
<script src="main.js"></script>
</body>
</html>
So first thing that we need to do to start working with Redux is create a store. What is store? It's this global object where we will store all our data of the application.
const store = Redux.createStore();
So with createStore function we created new store. If we look in browser we see the error
Expected the reducer to be a function
This happens because we must provide a reducer as a parameter to our createStore. And the question now is what is reducer. This is a function where we describe what data do we have in store and how our store will be changed. Let's say that we want to save in store only the list of users that we have.
const reducer = (state = []) => {
return state;
};
const store = Redux.createStore(reducer);
So here we created a reducer function where we have one single argument which is state. Also we are setting this argument to empty array by default. This is because our list of users is empty by default. As you can see we don't do anything is reducer and just return state.
But actually we got rid of the error in browser.
Now let's check what data we have in our store.
console.log(store.getState());
As you can see we are getting back an empty array. This is logical because by default we set our data inside store to empty array. So every time when we want to get data from the store we are writing store.getState().
Now let's say that we want to subscribe for this data in store in different parts of our application. So we want to be notified when our store changes.
store.subscribe(() => {
console.log('subscribe', store.getState());
});
So our store has a method subscribe and we can pass a callback inside. This callback will be called every time when our state changes. And we can use getState function in order to get information about current state.
Now when we subscribed to the changes from our state the question is how to change our state? For this we have a function dispatch inside store. What is dispatch? This is a function which triggers some change in our store. For example adding or removing a user is a dispatch. Clicking on the button can also call dispatch to change the state.
store.dispatch({ type: "ADD_USER" });
As you can see we passed inside an object with field type. This string inside type can be whatever string you want but passing an object with property type is mandatory.
Now when we look in browser we can see that our subscribe was triggered but it doesn't bring us anything.
Now we need in our reducer to react somehow on our dispatch and make changes. For this we have a second parameter action inside reducer. Let's console.log it.
const reducer = (state = [], action) => {
console.log("reducer", state, action);
return state;
};
So now in console we see 2 logs. First one is not from us. It's an action that Redux was initialized but our second action is exactly the data that we passed inside dispatch.
So every time when we make a dispatch it gets inside reducer where we can react on it and change the state. Let's change it now.
const reducer = (state = [], action) => {
console.log("reducer", state, action);
if (action.type === "ADD_USER") {
return ['foo'];
}
return state;
};
So just with simple if condition we can return some new state. If we look in browser here what happens.
- We dispatch action which is essentially an object with field type
- It comes inside reducer where we have access to a current state and our action
- We can update our state to completely new or just change some data inside
And as you see we are notified in subscribe that our state was change and we got a new state. And the most important is that our subscribe doesn't know anything about dispatch or actions it just gets new state back.
But of course we are returning array with foo which doesn't make much sense. What we normally do is we dispatch an action with some data inside. For example a username in our case. And then we can use all information from action to change our state.
store.dispatch({ type: "ADD_USER", payload: "jack" });
const reducer = (state = [], action) => {
console.log("reducer", state, action);
if (action.type === "ADD_USER") {
return [...state, action.payload];
}
return state;
};
So important point here is that we can add in the action any properties that we want. But to keep consistent the standard property to pass data in action is payload. We also changed our if condition and now we use both our current state and action.payload to return new data.
If we check in browser as you can see our state was correctly modified.
And here is super important point to understand how Redux is working. So Redux uses our reducer function and call it every time with current state and action that we passed in dispatch. So we dispatched ADD_USER action and Redux calls our reducer with current state and ADD_USER action. The action that is returned Redux saves internally every single time and of course notifies all subscribers that our state was changed.
Let's add one more use to see that it is working.
store.dispatch({ type: "ADD_USER", payload: "jack" });
store.dispatch({ type: "ADD_USER", payload: "john" });
As you can see our log in subscribe is shown twice. After first dispatch and after second dispatch.
Now let's add some DOM elements so you can see how we can use it with real example. So we want an input to type new user name, a button to add a user and a list of users.
<input type="text" class="userInput" />
<button class="addUser">Add user</button>
<ul class="list"></ul>
Now let's create variables for this 3 elements and add click event to the button.
const list = document.querySelector(".list");
const addUserBtn = document.querySelector(".addUser");
const userInput = document.querySelector(".userInput");
addUserBtn.addEventListener("click", () => {
store.dispatch({ type: "ADD_USER", payload: userInput.value });
});
So here we make our store dispatch when we click on button and we pass userInput.value inside. As you can see in browser our state is correctly updated.
Now we need to render a list of users.
store.subscribe(() => {
list.innerHTML = "";
userInput.value = "";
store.getState().forEach((track) => {
const li = document.createElement("li");
li.textContent = track;
list.appendChild(li);
});
});
So inside subscribe we go through array every time and append a DOM element in the list.
Now as you can see in browser our functionality is fully working based on Redux.
And this was everything that you need to know about how Redux is working internally. All other stuff is just a sugar around this concept.
Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!
📚 Source code of what we've done