zustand-controller
v0.1.2
Published
Use a controller class to implement your state and actions in zustand
Downloads
4
Readme
zustand-controller
Use a controller class to implement your zustand actions.
import { create } from 'zustand';
import { withActions } from 'zustand-actions';
import { StateController, bindActions } from 'zustand-controller';
interface Counter {
//--- State<Counter> ---
count: number;
//--- Actions<Counter> ---
increment: () => void;
decrement: () => void;
}
class CounterController extends StateController<Counter> {
private incrementBy(by = 1): void {
// The controller keeps track of the current draft
this.draft.count += by;
}
increment(): void {
this.setState(() => this.incrementBy(1));
}
decrement(): void {
// setState uses immer's produce, when you pass a function
this.setState(draft => draft.count--);
}
}
const useCounter = create<Counter>()(
withActions(
(set, get, api) => {
const controller = new CounterController(api);
return {
count: 0,
...bindActions(controller, ['increment', 'decrement'])
};
}
)
);
const { increment, decrement } = useCounter.getActions(); // Actions<Counter>
const { count } = useCounter.getState(); // State<Counter>
useCounter.setState({ count: 1 });
useCounter(state => state.count); // as hook
Installation
npm
npm install zustand-controller
bun
bun install zustand-controller
Slicing
Slicing works as usual using controllers.
interface Counter {
//--- State<Counter> ---
count: number;
//--- Actions<Counter> ---
increment: () => void;
decrement: () => void;
reset: (name: string) => void;
}
interface Name {
//--- State<Name> ---
name: string;
//--- Actions<Name> ---
rename: (name: string) => void;
}
class CounterController extends StateController<Counter & Name> {
increment(): void {
...
}
decrement(): void {
...
}
reset(name: string): void {
this.setState(() => {
this.draft.count = 0;
this.draft.name = name; // access to other slice
});
}
}
class NameController extends StateController<Name> {
rename(name: string): void {
this.setState(() => {
this.draft.name = name;
});
}
}
const useCounter = create<Counter & Name>()(
withActions(
(set, get, api) => {
const counterController = new CounterController(api);
const nameController = new NameController(api);
return {
count: 0,
name: '',
...bindActions(counterController, ['increment', 'decrement', 'reset']),
...bindActions(nameController, ['rename'])
};
}
)
);