Skip to content
react-global-state-hooks

Actions

Group state changes behind named functions, return values, call other actions, and extend a store from outside.

GuideTypeScriptTry an example

The problem this solves

Free-form setState calls scatter the rules for changing state across components. Actions give each change a name and keep the rules in one place. They are optional.

Define actions on a store

Each action is a function that returns a function. The outer function takes your arguments. The inner one receives the store tools.

todo-actions.ts
import { createGlobalState } from 'react-global-state-hooks';

export interface Todo {
  id: number;
  text: string;
  done: boolean;
}

export const useTodos = createGlobalState(
  { todos: [] as Todo[], nextId: 1 },
  {
    actions: {
      add(text: string) {
        return ({ setState }) => {
          setState((state) => ({
            todos: [...state.todos, { id: state.nextId, text, done: false }],
            nextId: state.nextId + 1,
          }));
        };
      },

      toggle(id: number) {
        return ({ setState }) => {
          setState((state) => ({
            ...state,
            todos: state.todos.map((todo) => (todo.id === id ? { ...todo, done: !todo.done } : todo)),
          }));
        };
      },

      // Actions can return values, and can call the store's other actions through `actions`.
      addMany(texts: string[]) {
        return ({ actions }) => {
          texts.forEach((text) => actions.add(text));

          return texts.length;
        };
      },
    },
  },
);

The tools passed to the inner function are setState, getState, setMetadata, metadata, getMetadata, subscribe and actions (the store’s own action object).

In components, the hook’s second item is the actions object:

tsx
const [todos, actions] = useTodos((state) => state.todos);
actions.add('Write docs');

Outside React use useTodos.actions.add(...). Whatever an action returns is returned to the caller, so an async action returns a promise.

Extend a store from outside

actions(store, config) binds an extra group of actions to a store you did not define, or to keep a file small. Actions in the same group call each other with this.

external-actions.ts
import { actions, createGlobalState } from 'react-global-state-hooks';

export const useCounter = createGlobalState(1);

// Extend any store with extra actions without touching its definition.
export const counterActions = actions(useCounter, {
  double() {
    return ({ setState, getState }) => {
      setState(getState() * 2);
    };
  },

  // Actions in the same group call each other with `this`.
  quadruple() {
    return () => {
      this.double();
      this.double();
    };
  },
});

actions<API>()({...}) (a template) lets you define actions before the store exists and bind them later with template(api). That is how you attach internal actions in onInit. See the TypeScript page for how to get API.

Documentation
↑↓ Navigate ↵ Open Esc CloseRGSH docs
Get started

Shared state. Precise subscriptions.
Built-in DevTools.