0.1.2 • Published 1 year ago

zustand-controller v0.1.2

Weekly downloads
-
License
-
Repository
-
Last release
1 year ago

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'])
            };
        }
    )
);
0.1.2

1 year ago

0.1.1

1 year ago

0.1.0

1 year ago