Skip to content

Counter

Task

Create the smallest useful controller-backed feature:

  • local state
  • one or two actions
  • explicit controller lifecycle

Solution

Use a controller with one atom, expose it as readonly state, and keep all changes inside explicit actions.

Code

ts
import { declareController, readonlyAtom } from '@nrgyjs/core';

export const CounterController = declareController(({ scope }) => {
  const count = scope.atom(0, { label: 'count' });

  return {
    state: {
      count: readonlyAtom(count),
    },
    increase: () => count.update((value) => value + 1),
    decrease: () => count.update((value) => value - 1),
  };
});

const controller = new CounterController();

controller.increase();
console.log(controller.state.count());

controller.destroy();

What to Watch Out For

  • expose readonly state to the view
  • keep writes inside named actions
  • destroy the controller when the feature ends

Common Mistakes

  • exposing writable atoms directly to the UI
  • mutating state from random external code
  • forgetting to destroy the controller in non-global flows