Deploy Containers Close to Your Users

This Engineering Education (EngEd) Program is supported by Section.

Instantly deploy containers globally. Section is affordable, simple and powerful.

Get Started for Free.

Getting Started with HookState Library

February 22, 2022

React.js is a mature JavaScript library for declarative and dynamic user interfaces. React.js breaks the UI into components. The concept of state is critical in React.js programming.

We need to know what a state is, how to maintain it efficiently, and how to deal with increasing complexity as the application expands.

In this article, we will learn the basics of state management in React.js using the Hookstate library.

Table of contents

Pre-requisites

As a pre-requisite, the reader must have the following:

Understanding state management

In a nutshell, state management is a pattern in which we control the communication and sharing of data across the reusable components of the modern frontend frameworks.

Our application encapsulates data in a data structure that reflects the logical state of the application that we can use to access and change to transition between various states.

The status of the application (“state”) changes as a result of the user’s actions.

A case study can be an e-commerce application. For example, an e-commerce website can have components such as Button, Cart, Checkout, Login, and many more.

When a user adds an item to the Cart component or performs a successful login, these actions will alter the state of our component and hence the entire application.

Why use state management libraries?

In modern frontend applications, we break the UI into logical reusable components. These components often need dynamic data to share and pass around.

In an extensive application, keeping track of the global state while avoiding prop drilling can be difficult. That is where state management libraries come in.

Unlike redux which uses reducers, dispatch, and actions that can sometimes be confusing, the Hookstate library takes the concept of state in React to a new level.

The Hookstate library wraps the idea of the declarative React useState to a global version and extends it with extra features.

Some of its core features include:

  • A plugin system to persist and state validate to extend the library features.
  • Hookstate’s standard TypeScript support for state management.
  • Support for asynchronous and partial state updates in deeply nested components and more.

Application setup

To scaffold a new React application, we will use a new frontend build tool, Vite.

Vite optimizes the build process for developers by bundling the pre-configured code using Rollup rather than Webpack.

To start a Vite app with a basic React template, type the following command:

npm init vite@latest hookstate-demo -- --template react

Next, navigate inside the hookstate-demo folder on the terminal and execute the npm install command:

npm install

Next, add the hookstate and uuid packages to the project as shown:

npm install --save @hookstate/core uuid

Lastly, spin up a development server on your browser by running the command:

npm run dev

terminal output

If we switch to our browser and access the URL http://localhost:3000/, we should see something similar to this:

browser demo

Create the global state

To create and manage a global state, add a folder in your src directory and name it states.

Now, we’ll create a TaskState.js file under the states folder containing a custom hook. Our function will invoke Hookstate’s method createState([]) to create a new state and return it.

Import the uuid and the @hookstate/core package to create a global state.

import { createState, useState } from "@hookstate/core";
import {v4 as uuid} from "uuid";

Note: The useState hook resembles React’s built-in hook. When accessing hooks simultaneously in a single file, an alias is helpful to eliminate ambiguity.

Below the library import, instantiate the createState to create a new state.

// Initial state - empty array.
const taskState = createState([]);

Lastly, let’s create a custom hook to reuse when manipulating the state in our components. Create and export the useTaskState function:

export function useTaskState() {
}

Inside the function body, add the state variable to initiate the state from the useState:

// assign state
const state = useState(taskState);

Finally, return the following functions:

return {
    // addTask method takes the new state and returns a new state using the .set(method)
    addTask(newTask) {
        return state.set((tasks) => [...tasks, { newTask, id: uuid() }]);
    },
    // filter task lists to remove a list item
    removeTask(id) {
        return state.set((tasks) => tasks.filter((task) => task.id !== id));
    },
    // state.get() retieves the Todo list state
    get getTasks() {
        return state.get();
    }
};

Let’s briefly dissect the above code snippet:

  • The addTask method accepts a newTask parameter that represents the user value in the input field. Finally, the function returns state.get from Hookstate to perform mutations and add a new task.
  • getTasks method will access the global store by returning the state. get method that works the same as React’s in-built setState hook.
  • Finally, the removeTask method accesses the global state and filters out the task by ID.

Create AddTodo component

The AddTodo component handles the user input to render a new to-do item. Define the AddTodo.jsx file inside the components folder.

Our component will reuse the previous custom useTaskState to access the global state:

import { useTaskState } from "../states/TaskState";

Inside our return statement, we add an input form that accepts a new to-do item. When a user submits the form, we invoke the onSubmit event handler to add the new item.

Create the AddTodo function as shown below:

const AddTodo = () => {
    const taskState = useTaskState();
    return (
        <div>
            <form
                onSubmit={(e) => {
                e.preventDefault();
                // trim white spaces
                if (!e.target["toDo"].value.trim()) {
                return;
                }
                // add new to-do item
                taskState.addTask(e.target["toDo"].value);
                e.target["toDo"].value = "";
                }}
            >
                {/*An input element and a button */}
                <input name="toDo" />
                <button type="submit">Add Todo</button>
            </form>
        </div>
    );
};

Finally, export our function by default:

export default AddTodo;

The TodoList component

The TodoList component contains our todo items. Inside your components folder, add the TodoList.jsx file with the code below:

import { useTaskState } from "../states/TaskState";

const ToDoList = () => {
    const taskState = useTaskState();
    const state = taskState.getTasks;
    return (
        <ul>
            {state.length > 0 &&
            state.map((todo) => (
                <li key={todo.id}>
                    <span>{todo.text}</span>
                    {/*Add a delete button*/}
                    <button onClick={() => taskState.removeTask(todo.id)}>
                    Delete
                    </button>
                </li>
            ))}
        </ul>
    );
};

export default ToDoList;

In the above code, we do the following:

  • First, we import the useState custom hook from our states folder.
  • const state = taskState.getTasks; is the variable to access our state.
  • Inside the JSX, we return an <ul> element with lists of available tasks by looping over them.

The App.js component

Our main App.js file is quite minimal. All we need to add is the ToDoList component, AddTodo component, and useTaskState.

import { useTaskState } from "./states/TaskState";
import ToDoList from "./components/ToDoList";
import AddTodo from "./components/AddTodo";

Finally, export the App component with the components mapped to the JSX.

export default function App() {
    const taskState = useTaskState();
    return (
        <div className="App">
            <h1>TODO APP</h1>
            <AddTodo />
            <ToDoList />
        </div>
    );
}

Demo

To run the program, spin up a development server on your terminal with the command:

npm run dev

If we head back to our browser at http://localhost:3000/, our final app should look similar to this:

todo demo

Conclusion

This tutorial introduced you to state management in React with Hookstate. To generate the global state and access the state store, we built a Todo app that uses the library’s APIs.

You can find the project source code on GitHub.

Happy coding!

Further reading


Peer Review Contributions by: Srishilesh P S