TL;DR
- Class-based models: fields are state, methods are logic.
- Hooks-first API:
useModel,useInstance,useWatcher. - Deep watching and DI are built in.
- Instance caching by args makes state partitioning natural.
Why it exists
Most state libraries start with a store. easy-model starts with a model class. That shift makes domain logic cohesive and testable. You describe business behavior once, then subscribe to it in React with minimal glue.
A minimal example
import { useModel, useWatcher } from "easy-model";
class CounterModel {
count = 0;
label: string;
constructor(initial = 0, label = "Counter") {
this.count = initial;
this.label = label;
}
increment() {
this.count += 1;
}
decrement() {
this.count -= 1;
}
}
function Counter() {
const counter = useModel(CounterModel, [0, "Demo"]);
useWatcher(counter, (keys, prev, next) => {
console.log("changed:", keys.join("."), prev, "->", next);
});
return (
<div>
<h2>{counter.label}</h2>
<div>{counter.count}</div>
<button onClick={() => counter.decrement()}>-</button>
<button onClick={() => counter.increment()}>+</button>
</div>
);
}
Practical wins
- Cohesive logic: no action/reducer splits.
- Deep watching: observe nested changes without extra plumbing.
- DI built in: explicit dependencies, easier tests.
- Natural partitioning: instance caching by args.
If your team already models domain logic with classes, easy-model feels natural with minimal migration cost.
GitHub: easy-model
npm: @e7w/easy-model
Top comments (0)