Let's implement a simple example to turn on and turn off the light. We can build a simple robot that just listens to commands and, based on the commands, performs some actions. For simplicity, suppose that our robot can only understand two commands, as follows:
- TURN_ON
- TURN_OFF
Now, let's build our robotic function:
const tubeLight = (state = "OFF", action) => {
switch (action.type) {
case "TURN_ON":
return "ON";
case "TURN_OFF":
return "OFF";
default:
return state;
}
};
This is a simple JavaScript function that takes the initial state and action as parameters and returns a state. That sounds like something familiar, doesn’t it? Yup; you are right. This is a simple reducer function.
In the first section, you learned Redux's first principle: a single source of truth. Redux provides a function called createStore that takes the main reducer file and creates the store. Let's create a store, as follows:
import { createStore } from "redux";
const store = createStore(tubeLight);
So far, so good. So, what did we do here? We imported the createStore function from the Redux library that is given tubeLight, which is a reducer, as an argument and is saved into a variable called a store. Here, you can recall a functional programming concept. A function can consume another function. Now, as you have already seen, the store has three methods: getState, dispatch, and subscribe. Let's use them.
log the initial state, as follows:
console.log("Initially tubelight is: ", store.getState());
Try to build it, and run it again (yarn build && yarn start). Check the console:
Initially tubelight is: OFF
Nothing complex, right? We provided the initial state to OFF, and it logged the initial state as OFF. That looks good. Now, let's try to modify the store. In other words, we should instruct the robot to turn on the tubelight. Remember, we can only modify the store by using a dispatch function. Now, we can use that function and log the state, in order to see the state change:
store.dispatch({ type: "TURN_ON" });
console.log("Now tubelight is: ", store.getState());
The output that you get on the console should be as follows:
Now tubelight is: ON
Now, it makes sense, right? Let's go further and display the state on the browser, rather than on the console. To do that, let's create a button. When we press the button, it should toggle the tubelight state. That is to say, if the tubelight is ON, we turn it off, and vice versa. To make it simple, let's forget about React and use native JavaScript:
const button = document.createElement("button");
button.setAttribute("id", "lightButton");
var text = document.createTextNode("Toggle Light");
button.appendChild(text);
document.body.appendChild(button);
The preceding snippet will create a simple button on the browser, with the text Toggle Light and the ID lightButton.
Now, we need to add an event listener. That is to say, if the tubelight is on, we turn it off by clicking on the button. We can do that as follows:
document.getElementById("lightButton").addEventListener("click", () => {
if (store.getState() === "ON") {
store.dispatch({ type: "TURN_OFF" });
} else {
store.dispatch({ type: "TURN_ON" });
}
});
Now, let's render that in the browser, inside of the body tag:
const render = () => {
document.body.innerText = store.getState();
document.body.appendChild(button);
};
This will render the initial state of the store. But we need to display when the state changes. To do that, our third method of the store comes into play (subscribe()):
store.subscribe(render);
render();
Now, try to build the app and run it (yarn build && yarn start). Try to click on the button to change the state, and see whether the state is reflected on the browser. Pretty sweet, right? You can find the working example of this code in the GitHub repository, inside CH01/getting-started.
Manually updating the DOM does not scale in a real application. To do so, we use the help of other libraries, such as React. We will configure React with Redux and use it to understand other complex scenarios in Redux.