Nefe James Nefe is a frontend developer who enjoys learning new things and sharing his knowledge with others.

Managing state with Elf, a new reactive framework

4 min read 1302

Introduction

State management is the process of controlling how the state is updated and passed from one component to another. Regardless of the library or framework we use, state management is an essential part of developing JavaScript applications.

When working with a library like Redux, we have to set up actions, reducers, and <Provider store={store}> to get our application state working. Elf simplifies state management for us by reducing the hassle of creating repetitive, boilerplate code in our applications.

In this article, we will learn about Elf, a new state management library. We’ll cover its features and how we can use it to manage the state in our applications.

Why do we need state management?

State management is one of the challenging aspects of developing applications. When building web applications, we can store the most primitive and basic states locally in the components that need them. However, as our applications grow bigger, managing shared states across multiple components becomes difficult.

When this happens, state management becomes increasingly complex, and we begin to have issues such as prop drilling and state falling out of sync among different UI components.

These, and more, are the problems developers solve by building state management libraries such as Elf.

What is Elf?

Elf is a reactive and immutable state management library built on top of RxJS. Elf provides us with a wide arrange of tools to manage our state. Because of this, there is some terminology we should know, like observables, observers, and subscriptions.

Observables are objects that can emit data over a period of time. They function as wrappers around data sources or stream of values

Observers are consumers of the data observables store. They execute a piece of code if the data being observed is mutated or if an error occurs, and react to state changes. They also implement up to three methods: next, error, and complete. We will not look at these in detail because they are specific to RxJS and therefore beyond the scope of this article.

Subscriptions are how we connect observers to observables. Observers subscribe to observables, watch for any changes in the data, and react to those changes.

We made a custom demo for .
No really. Click here to check it out.

Installation

Run the command below in your terminal to install Elf:

npm i @ngneat/elf

The Elf store

At the center of every Elf application is the “store”. A store is a container that holds our application’s state. We can think of a store like a database.

An Elf store takes an object that contains three properties — a state, a name, and config.

Let’s see how the store works by creating a state with it:

import { Store, createState, withProps } from '@ngneat/elf';

const { state, config } = createState({
  data: { name: "John", email: "[email protected]" },
});

const formStore = new Store({ state, name: 'userData', config });

The createState method returns the state and config objects, which we use to create the store.

Accessing the store

Elf stores are observables, so we can subscribe to them and get their values like so:

formStore.subscribe((state) => {console.log(state)});

The select operator

The select operator enables us to select a “slice” (or a specific part) of a store.

For example, say we had the store below:

const dummyStore = {
  todos: [
    { text: "Learn Elf", completed: true },
    { text: "Use Elf", completed: false },
  ],
  users: [ { name: "Jack" }, { name: "Jill" } ],
};

Each key/value pair in the dummyStore object is a slice; dummyStore.todos and dummyStore.users are slices.

Now let’s see how the operator works:

import { select } from '@ngneat/elf';

const userEmail = formStore.pipe(select((state) => state.data.email));

The select operator only runs when the state changes or when there is a new reference to the selected state.

We use the pipe operator to chain multiple functions together to keep our code readable.

Elf entities

Elf entities are unique types of Elf stores. Entities act in the same manner as tables in a database, and we can store large collections of similar data in entities.

For example, if we had a clothing ecommerce store with data on shoes, shirts, and sneakers, entities would be the right place to store that data.

We can set up entities in Elf using the ngneat/elf-entities package. We can also run queries and mutations on these entities using the different query and mutation methods Elf provides, which I will explain below.

Entity queries

Elf provides several queries that we can use to run query operations on entities. Let’s look at some of these query operations.

The selectFirst query returns the first entity in a store. You can use it like so:

import { selectFirst } from '@ngneat/elf-entities';
const users = usersStore.pipe(selectFirst());

The selectLast query returns the last entity in a store:

import { selectLast } from '@ngneat/elf-entities';
const users = usersStore.pipe(selectLast());

The selectAll query returns all the entities in a store’s collection:

import { selectAll } from "@ngneat/elf-entities";
const users = usersStore.pipe(selectAll());

Entity mutations

There are several methods we can use to mutate Elf entities.

We can use the addEntities mutation to add entities to a store. We can add multiple entities to a store by passing an array of data to addEntities like so:

import { addEntities } from '@ngneat/elf-entities';

//add a single entity
usersStore.update(addEntities(user));

//add multiple entities
usersStore.update(addEntities([user1, user2]));

We can add single or multiple entities from a store using the deleteEntities mutation. To delete multiple entities, we pass in an array containing the IDs of the entities we want to delete:

import { deleteEntities } from '@ngneat/elf-entities';

//delete a single entity
usersStore.update(deleteEntities(id));

//delete multiple entities
usersStore.update(deleteEntities([id, id]));

We can update the entities in a store using the updateEntities mutation:

import { updateEntities } from '@ngneat/elf-entities';

usersStore.update(updateEntities(id, { name }));

The persistState function

The persistState function enables us to persist some of the app’s state by saving it to a browser’s local or session storage.

We need to install the elf-persist-state package before we can use persistState function. Run the command below in your terminal to install the package:

npm i @ngneat/elf-persist-state

Now, let’s see how persistState works:

import { Store, createState, select } from "@ngneat/elf";
import {
  persistState,
  localStorageStrategy,
  sessionStorageStrategy,
} from "@ngneat/elf-persist-state";

const { state, config } = createState({
  data: { name: "John", email: "[email protected]" },
});

const formStore = new Store({ state, name: "userData", config });

export const persist = persistState(formStore, {
  key: "auth",
  storage: localStorageStrategy,
});

The persistState function takes two parameters. The first is the store we want to persist, and the second is an options object. We define the key and storage in the object.

The key is the name under which we save the persisted state. The key acts as the state’s label or identifier. The storage is where we define the strategy we want to use to persist the state.

The elf-persist-state package provides two storage strategies, localStorageStrategy and
sessionStorageStrategy. We can choose the strategy that best fits our application’s needs. Here, we used the localStorageStrategy.

Conclusion

We have gotten a brief intro to Elf and some of its functionality. However, Elf has a lot more to offer. A big selling point of Elf is its low learning curve. Compared to alternative state management solutions such as Redux, Elf is a beginner-friendly library, and easy to work with.

An issue I have with Elf is its documentation. The documentation is lacking in a lot of useful context that will make the library even easier to learn. There is also a scarcity of examples that would help show Elf’s full capabilities.

I would use Elf because of the low learning curve, but only for personal or pet projects. Take note that it is still a relatively new library, so check it out in the docs and familiarize yourself with this awesome state management framework.

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Nefe James Nefe is a frontend developer who enjoys learning new things and sharing his knowledge with others.

2 Replies to “Managing state with Elf, a new reactive framework”

  1. No matter how many state libraries I read about or test myself, nothing is as simple and usable as Zustand

Leave a Reply