How to Create and Update Store

Best practices for creating and updating store

We recommend encapsulating the state modification logic within your store for cleaner, more maintainable code. This keeps your components focused on presentation while centralizing business logic.

const counterStore = createStore({
  count: 0,
  increment() {
    // Use the store instance to mutate the state directly
    counterStore.setState((state) => {
      state.count++;
    });
  },
  // Async actions are also supported
  async incrementAsync() {
    await new Promise((resolve) => setTimeout(resolve, 1000));

    // Access current state with `store.value`
    const currentCount = counterStore.value.count;

    // Call other store actions
    counterStore.value.increment();
  },
});

// Clean API calls
counterStore.value.increment();
await counterStore.value.incrementAsync();

State Update Patterns

Let's explore different approaches using a realistic user store:

const userStore = createStore({
  name: "John",
  followers: 0,
  settings: {
    language: "en",
    theme: {
      primary: "blue",
    },
  },
  updateSettings(newSettings) {
    userStore.setState((state) => {
      state.settings = newSettings;
    });
  },
});

Best for partial updates and stores with actions. Immer handles immutability automatically.

// Natural and readable
userStore.setState((state) => {
  state.followers++;
  state.settings.theme.primary = "red";
});

So you don't need to use store.value to read state and spread it like this:

userStore.setState({
  ...userStore.value,
  followers: userStore.value.followers + 1,
  settings: {
    ...userStore.value.settings,
    theme: {
      ...userStore.value.settings.theme,
      primary: "red",
    },
  },
});

2. Direct Object Updates

Ideal for simple stores without actions or complete state replacements.

const counterStore = createStore({ count: 0 });

counterStore.setState({
  count: counterStore.value.count + 1,
});

But it's more troublesome for complex state updates, you need to manually spread the original state.

For example, update a store with actions:

userStore.setState({
  ...userStore.value, // spread the entire state with original actions
  followers: userStore.value.followers + 1, // update the followers
});

3. Partial State Merging

Luckily, ZenBox allows you to update partial state like this:

userStore.setState({
  name: "Jane",
  followers: userStore.value.followers + 1,
  age: 18, // new properties are ignored, existing structure preserved
});

What a life saver!

Notes:

  • Only first-level merging is supported
  • For nested updates, use the Immer approach

4. Direct Value Assignment

You can also use store.value = x to update state directly.

// Complete replacement
userStore.value = {
  name: "Jane",
  followers: 100,
  settings: {
    language: "zh",
    theme: {
      primary: "red",
    },
  },
};

// Partial replacement (same as setState)
userStore.value = {
  name: "Jane",
  followers: userStore.value.followers + 1,
};

Notes:

  • Can be confusing for partial updates
  • Prefer Immer-style for complex changes