I'm pleased to announce rmemo, a tiny no-fluff reactive state library. rmemo is the reactive core of relementjs, a server & browser UI rendering library that I also released.
What is rmemo?
rmemo is a tiny no-fluff state management library. It offers reactive memos & reactive signals for the server & browser. This includes:
- reactive memos
- reactive signals
- autosubscriptions
- async support
- a terse & focused api
- performance
- integration with garbage collector
imports size memo_ 338 B memo_ + sig_ 354 B memo_ + sig_ + be_ + ctx_ 506 B memo_ + sig_ + be_ + ctx_ + be_memo_pair_ + be_sig_triple_ 602 B It looks something like:
// users.ts import { sig_ } from 'rmemo' export const user_a$ = sig_<User[]>([], user_a$=> fetch('https://an.api/users') .then(res=>res.json()) .then(user_a=>user_a$.set(user_a))) export function user__add(user:User) { user_a$([...user_a$(), user]) } export interface User { id:number name:string }
Garbage Collection Integration
rmemo tracks listeners using WeakRef. Most other reactive state management libraries track listener references. This means the listener must unregister itself once the listener is complete. Let's examine the trade-offs:
Motivation
Until recently I was using Nano Stores for my goto state management solution. I contributed to fixing diamond dependency issues. I also wrote some extension libraries[1]. Nanostores is small, usable on the server & browser, & works with any UI rendering library. All seemed well & I used Nanostores for some large projects. The api is cumbersome in a few ways:
computed
requires it's parents to be listed as arguments.import { atom, computed } from 'nanostores' const user_cache = { 1: { id: 1, name: `Joe Blo` } } const id$ = atom(1) const user$ = computed(id$, id=>user_cache[id])
async operations must use a writable
atom
&subscribe
[2]import { atom } from 'nanostores' const id$ = atom(1) const user$ = atom() id$.subscribe(async id=>{ const user = id ? await user__get(id) : null user$.set(user) }) function user__get(id:number) { return fetch('https://my.api/users/' + id) .then(res=>res.json()) }
Should be smaller
atom atom + computed atom + computed + contexts (next release) 298 B 1013 B > 1200 B The bundle size of nanostores is tiny when only using
atom
but grows over 1 kb when includingcomputed
.
The next major version will integrate
task
withcomputed
.