Rematch - a better Redux?
Recently, declaring Redux dead has become pretty popular in the web development community. While this isn’t necessarily true, it encourages developers to look for Redux alternatives and other state management solutions.
Rematch is one such solution. It builds upon a strong foundation that is Redux core while limiting the boilerplate, following Redux best practices, and providing a great development experience. Let’s take a closer look and see how it compares to Redux!
Rematch
Rematch isn’t a new library. It’s been around for about four years now and has been steadily growing in popularity. Being based on Redux, it’s only a bit larger than the Redux core itself - 4.3 KB vs. 4.7 KB (about 1.7 KB Gzipped), and yet it manages to remove tons of boilerplate and provide a whole lot of additional features.
To give you an overview of some of the Rematch’s features:
- Built on Redux - allowing for easy migration, code interoperability, use of Redux Devtools, and more;
- Reduced boilerplate - switch statements, thunks, and others are handled out-of-the-box;
- Written in TypeScript - with all the autocompletion goodness included;
- Plugin API - easily extend Rematch with custom or first-party plugins;
- Framework-independent - works great with React, but also Vue, Angular, and others;
- Built-in side-effects - without redux-thunks, just
async
/await
;
As you can see, a lot is going for this library, and with a focus on development experience, it looks to be an excellent choice for your next project.
Getting started with Rematch
To see how it’s like to use Rematch, let’s take it for a test drive to experience its API and learn its concepts.
Start by installing the library:
npm install @rematch/core
With this done, you’re ready to jump in and create your first Rematch model.
const countModel = {
state: 0,
reducers: {
increment(state, payload) {
return state + payload;
},
},
effects: (dispatch) => ({
async incrementAsync(payload) {
await new Promise((resolve) => setTimeout(resolve, 1000));
dispatch.count.increment(payload);
},
}),
};
Models are at the heart of Rematch. They’re the main driving force behind boilerplate reduction and help to enforce Redux’s best practices.
To create a model, all you need is to define an object with specific properties. You can do that either directly or with createModel()
helper for type interference.
A model uses properties such as:
state
- For defining initial state;reducers
- To contain pure functions for conducting state changes;effects
- For async side-effects.
These and other properties encapsulate and simplify most of Redux’s boilerplate to a single object with a given set of functionalities. In the above example, countModel
contains the counter state, as well as the reducers and effects to change it.
To use your model, create a new store using the init()
function.
import { init } from "@rematch/core";
// ...
const store = init({
models: {
count: countModel,
},
});
The init()
function accepts a config object with properties like models
or plugins
and returns a fully-configured Redux store with additional Rematch functionality.
With the above snippet, we’re creating a new store using the previously-defined countModel
- here registered under a name count
.
The created store has all the functionality of a Redux one, including methods like dispatch()
or subscribe()
. On top of that, Rematch inserts there its own, custom features like the addModel()
method for lazy-loading new models or shortcut action dispatchers under dispatch
. The latter is especially helpful in changing your state.
// ...
const { dispatch } = store;
dispatch({ type: "count/increment", payload: 1 });
dispatch.count.increment(1);
dispatch({ type: "count/incrementAsync", payload: 1 });
dispatch.count.incrementAsync(1);
With action dispatchers, you can access all your reducers and effects functions with a simplified API under dispatch[MODEL_NAME]
. Personally, I consider this approach much cleaner and more enjoyable than a direct dispatch()
function.
So that’s pretty much everything you need to know about Rematch to get started. Of course, there’s a lot more Rematch has to offer, like plugins, Redux Devtools integration, compatibility with integrations like react-redux, and more. However, the basics are straightforward, and you can slowly pick up the other features if and when you need them.
Open Source Session Replay
OpenReplay is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data.
Start enjoying your debugging experience - start using OpenReplay for free.
Redux Toolkit vs Rematch
The only question left to answer is how Rematch compares against Redux Toolkit. After all, the Toolkit is currently the go-to for modern Redux development and provides very similar features to Rematch.
Like Rematch, Redux Toolkit minimizes the boilerplate, follows best practices, and provides a good development experience. It also has some additional features like RTK Query.
Personally, I think Rematch is a better choice for most projects - especially if you’re starting from the ground up. Not only it’s easy to understand, clean and simple, but it can also be easily extended when needed using its plugin API. Redux Toolkit is simply a bit more complex tool to understand, slowing down the development.
Bundle size and performance are also something to consider. 32.1 KB vs. 4.7 KB is not a small difference. Sure, Redux Toolkit has more features built-in, but you might not need all of them, and Rematch’s plugin API gives you more control over what’s used.
Bottom line
All in all, I’d recommend you give Rematch a try. It’s easy to learn and enjoyable to use - whether you’re a new or experienced Redux user. Its minimalistic and approachable API makes for a great development experience and thanks to its Redux roots you can always draw from Redux’s established ecosystem if and when that’s needed.