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.
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 including computed
.
[1]: @ctx-core/nanostores & @ctx-core/solid-nanostores
[2]: The next major version will integrate task
with computed
.