Rematch – Redux without boilerplate code

Stanislav Bykov

Frontend developer at Yuztech Group of Companies

Today I’d like to talk about Rematch, a library that provides a convenient and efficient way to manage the state of your web applications. If you are already familiar with Redux and are looking for a simpler and more compact solution, then Rematch may be a useful tool for you.

In this article, I’ll introduce you to the main benefits of Rematch and show you how to easily and effectively use it to manage the state of your applications. I think that, regardless of your experience in development, you will find useful information that will help you in your daily work.

Rematch offers a convenient syntax and allows you to avoid writing the numerous boilerplates inherent in Redux. With it, you can quickly create and organize a Redux repository, saving time and simplifying the development process. Rematch is ideal for various types of projects, regardless of their size and complexity.

With Rematch you can define models and their states, effects and reducers. It provides convenient tools for working with asynchronous operations, as well as the ability to create selectors for retrieving data from storage. All of this helps you organize your application’s logic and manage its state with minimal effort.

First of all, I would recommend this library to those who are just starting to learn application state management or are writing a new project from scratch, because Rematch is much easier to learn than many other libraries, provides a much nicer interface, and is also much more easier.

Introduction to Rematch

Rematch is an intuitive and lightweight framework for managing the state of your Redux-based web application. It offers a simple and effective approach to organizing and managing Redux storage, reducing unnecessary code and simplifying development.

Rematch is not only a state management tool, but also a development philosophy. His goal is to make the code more understandable, easily maintainable and scalable. One of the key features of Rematch is its integration with Redux without the need to write numerous boilerplate codes and settings. This allows developers to start using it faster and focus on the business logic of their application.

While working with the library, I noted the following: useful features:

  • small size (less than 2Kb);

  • no configuration required;

  • built-in support for side effects;

  • support for Redux Devtools, TypeScript;

  • support for dynamically adding reducers, hot reloading;

  • the ability to create multiple storages;

  • Extensibility of functionality using plugins;

  • Possibility of use in React Native.

If we compare Rematch with direct use of Redux, it Main advantages:

  • Simplicity and clear syntax. Rematch offers a simple and intuitive model that allows you to define state models, effects, and reducers with a minimum amount of code. It frees developers from having to write numerous actions, constants, and reducers, which makes the code more concise and understandable.

  • Modularity and reusability. Rematch allows you to organize your application code into modules (models), which promotes logical separation of functionality and code reuse. You can create independent models containing their own state, reducers, and effects, and combine them into one store.

  • Powerful Effects. Rematch provides an easy way to define and handle asynchronous operations and side effects using effects. It integrates with the Redux middleware, making it easy to manage asynchronous requests, API calls, and other side effects.

  • Extensibility. Rematch makes it easy to extend functionality using plugins. You can use ready-made plugins or create your own to add new features and integrations to your application.

Despite the advantages presented, it is important to understand that Rematch is only a wrapper over Redux, which provides developers with a simplified API. Performance problems and additional functionality, unfortunately, will not be solved by switching from using Redux to Rematch.

Basic Rematch Concepts

Here I’ll show basic Rematch concepts that will help you organize and manage your application’s state.

Models

Models are a key concept in Rematch. They are independent blocks of code containing state, reducers, and effects. Each model has a unique name and can be combined with other models into one store.

Let’s create a simple “counter” model that will contain the counter state and reducers to increment and decrement it, as well as an effect to increment it asynchronously:

/* ./models/count.ts */

import { createModel } from "@rematch/core";
import { RootModel } from ".";

export const count = createModel<RootModel>()({
  state: 0, // начальное состояние
  reducers: {
    increment(state, payload: number) {
      return state + payload;
    },
    decrement(state, payload: number) {
      return state - payload;
    },
  },
  effects: (dispatch) => ({
    async incrementAsync(payload: number, state) {
      await new Promise((resolve) => setTimeout(resolve, 1000));
      dispatch.count.increment(payload);
    },
});

export default counter;
import { Models } from "@rematch/core";
import { count } from "./count";
import { example } from "./example";

export interface RootModel extends Models<RootModel> {
  count: typeof count;
  example: typeof example;
}

export const models: RootModel = { count, example };

Storage

A warehouse is a combination of several models into one data structure. It is the single source of truth for your application and stores the state of all models.

To create the store, Rematch uses the init function, which takes an object with models:

import { init, RematchDispatch, RematchRootState } from "@rematch/core";
import { models, RootModel } from "./models";

export const store = init({
  models,
});

export type Store = typeof store;
export type Dispatch = RematchDispatch<RootModel>;
export type RootState = RematchRootState<RootModel>;

Dispatch actions

With Dispatch you can call your models’ reducers and effects. The dispatcher can be called in the usual way, as in Redux, or with a short entry:

const { dispatch } = store;

dispatch({ type: "count/increment", payload: 1 });
dispatch.count.increment(1);

dispatch({ type: "count/incrementAsync", payload: 1 });
dispatch.count.incrementAsync(1);

Access to status and actions

To access the state and actions of models in your application components, you can use the useSelector hook and the dispatch method:

import * as React from "react";
import { useSelector, useDispatch } from 'react-redux';
import { RootState, Dispatch } from './store';

const CounterComponent = () => {
  const count = useSelector((state: RootState) => state.count);
  const dispatch = useDispatch<Dispatch>();

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => dispatch.count.increment(1))}>Increment</button>
      <button onClick={() => dispatch.count.decrement(1))}>Decrement</button>
    </div>
  );
};

export default CounterComponent;

In this example, we use the useSelector hook to get the “counter” state value from storage, and the dispatch method to call the appropriate reducers.

Effects

In Rematch, effects provide the ability to perform asynchronous operations, such as querying the server or processing data. They allow you to easily manage side effects in your application.

To add effects to the model, you can use the effects keyword and define the necessary methods. Let’s add an effect to load data from the server:

const counter = createModel<RootModel>()({
  state: 0,
  reducers: {
    // ...
  },
  effects: {
    async fetchData(payload, rootState) {
      try {
        const response = await fetch(`http://example.com/${payload}`);
        const data = await response.json();
        // Действия с полученными данными
      } catch (error) {
        // Обработка ошибок
      }
    },
  },
});

Plugins

Rematch provides the ability to expand functionality using plugins. Plugins allow you to add additional features or change Rematch’s behavior to better suit your needs. They can override the configuration, add new models, or even replace the entire storage.

There are many plugins available for use with Rematch. Some of them were written directly by the team behind this library, but there are also some that were created by the community on npm/github, and no one forbids you to write your own plugin.

Below you will find a brief description of the plugins created by the Rematch team:

  • @rematch/immer: Wraps your reducers with the immer library, allowing you to safely perform state changes via mutations while keeping the state immutable.

  • @rematch/select: Adds the ability to use selectors to select data from a state. Selectors are created using the default reselect library and are automatically linked to selector dependencies from other models.

  • @rematch/loading: Plugin for displaying loading indicators when performing effects. Helps avoid manually managing download state by adding automatic download support to Rematch.

  • @rematch/updated: A plugin that allows you to support timestamps when calling effects. It is used primarily for optimizing effects and can be used to prevent expensive queries from running for a certain period of time or to limit the frequency at which effects are executed.

  • @rematch/persist: Provides automatic Redux state persistence. This allows you to save state between page reloads or after closing and reopening an application.

  • @rematch/typed-state: Designed to check state types at runtime. Uses prop-types to describe the expected form of types.

Bottom line

In this article, I talked about Rematch, a powerful application state management library. Based on his experience, he highlighted the main advantages of Rematch and showed in practice how to easily and effectively use it to organize Redux storage and manage state.

Rematch offers a simple, easy-to-use syntax that greatly reduces the amount of boilerplate associated with Redux, and I think this can make it an attractive tool for casual developers who want to focus on application development rather than the complexities of state management.

With support for many plugins, Rematch can be easily extended and tailored to your specific needs. We looked at some popular plugins such as a plugin for persisting state using redux-persist, a plugin for using immer.js, and a plugin for creating selectors using reselect.

I will note that Rematch is constantly evolving and improving, and you can explore additional features by studying the source code of the plugins or creating your own plugins.

I hope this article helped you understand the benefits and capabilities of Rematch and inspired you to use it in your projects. The library offers simplicity, compactness and scalability, making the development process more efficient and enjoyable.

If you have experience using Rematch, share it in the comments.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *