# Implement a State Manager

After you understand the "outer" syntax of using `defineState` to create a state manager, it's time to learn more about the internal implementation of a state manager.

## State Management Primitives

### `defineState` Function

Use the `defineState` function to define a state manager. When you call `defineState`, you provide a callback function. This callback receives an object with specific instances of state manager functions (primitives) that you use to define your state manager's behavior. `defineState` returns a function that, when invoked, gives you an instance of your state manager.

## State Properties (State Values)

Properties represent the internal, consistent state of your state manager. Use the primitives `atom` and `computed` to create reactive properties that connect with the rest of LWC's reactivity system.

### `atom(myValue)`

Represents a single, reactive piece of data. Changes to an `atom` trigger updates in components that use it, and re-computation of dependent derived values.

Provide an argument *`myValue`* to set the initial value.

The result of calling the `atom()` function is a reactive "atomic" value, which is essentially a wrapper around a piece of data that LWC can use to make components and other state managers reactive to changes in that data. Change the value of an `atom` only by using the `setAtom` primitive function.

Save the result of calling `atom` in a `const` variable, and return any `atom`s your state manager makes public in the state manager definition function's `return` statement.

:::note
You don't need to expose every `atom` in the return object. Atoms that are used only for internal state management — like the `config` atom in [Nested State Manager Example](/docs/platform/lwc/guide/state-management-example-nested.md) — can be omitted from the return statement.
:::

:::important
You can use `atom()` to wrap any JavaScript value, but it's recommended to stick to JSON-serializable values or `undefined` for best compatibility.
:::

### `computed([independentValues], computationFunction)`

Represents data that's derived from one or more `atom`s or other `computed` values. A `computed` property automatically recalculates after its dependencies change.

Provide as arguments an array of values *`[independentValues]`* upon which the `computed` value is dependent, and an anonymous *`computationFunction`* that determines the derived value. The anonymous function receives as parameters the new or current values of the values upon which it depends, which it can use to calculate the new dependent value.

:::tip
The formal explanation might read like gibberish, so here's something specific, taken from the succeeding example. `doubleCount` is twice `count`. This line is how that's implemented.

```javascript
const doubleCount = computed([count], (countValue) => countValue * 2);
```

`doubleCount` is a `computed` property. The `[count]` array is the first argument to `computed`, which means that `doubleCount` depends on `count`.

When `count` changes, the anonymous function recalculates the value of `doubleCount` as needed. It takes the same number of parameters as the *size* of the array in the first parameter, in this case, one: `countValue`. `countValue` is the value of `count` after the change. The result of the anonymous function is `countValue * 2`, and here it's implicitly returned.

This is about the simplest `computed` value possible. For a non-trivial example, including default values and an explicit `return`, see [Nested State Manager Example](/docs/platform/lwc/guide/state-management-example-nested.md).
:::

Save the result of calling `computed()` in a `const` variable, and return any `computed`s that your state manager makes public in the state manager definition function's `return` statement.

:::note
Like `atom` values, `computed` values used only within the state manager's implementation don't need to be included in the return object.
:::

## Actions (Functions)

Actions are functions defined by your state manager that contain logic to modify your state `atom` properties using the `setAtom` primitive. Actions are a part of the internal implementation of your state manager, and ensure that your state manager always maintains a consistent state. Public actions allow components and other state managers to interact with your state manager.

Define actions as anonymous functions, which can accept any parameters you want. Actions can return a value of any type, or no value. Actions can be synchronous or asynchronous.

:::tip
Here's a specific action, `setCount`, taken from the full example later in this topic.

```javascript
// Create an action that directly sets a new value for the `count` atom
const setCount = (newValue) => {
  setAtom(count, newValue);
};
```

Here, the action is `setCount`, and it accepts one parameter, `newValue`, which is (unsurprisingly) the new value to set `count` to.
:::

Save the action function in a `const` property. Return any actions that your state manager makes public in the state manager definition function's `return` statement.

:::note
Actions are a part of a state manager's implementation, and possibly part of the state manager's public API, but are otherwise "just functions". This offers flexibility, but just because you *can* do something doesn't mean you *should.*

For example, it's a best practice to always return a consistent shape for the state manager instance (same property names and value types, and the same actions). While possible, the following code would be an anti-pattern:

```javascript
if (initialValue % 2 === 0) {
  // Don't do this
  return { count, increment, divideBy2: () => setAtom(count, count.value / 2) };
}

return { count, increment };
```

This anti-pattern would cause some instances of the state manager to include an additional action. Consumers of the state manager can't rely on the extra action always being available.
:::

## State Manager Public API

The callback function that you provide to `defineState` returns an object with references to the values and actions that your state manager makes available to its consumers. Your components access this public API via the `value` element of the state manager instance.

In this example, the function returns two values (one `atom`, one `computed`) and two actions:

```javascript
return {
  count, // the counter value (atom)
  doubleCount, // a computed, dependent value
  increment, // an action to increment the counter value by +1
  setCount, // an action to set the counter to an arbitrary value
};
```

A consumer component or template accesses the values using the `.value` element of the counter state manager instance:

```html
<section class="slds-p-around_small">
  <p>Count: {counter.value.count}</p>
  <p>Doubled: {counter.value.doubleCount}</p>
</section>
```

Actions are accessed in a similar way from the component. To use them from the template, create an action handler in your component to connect the two together.

```javascript
handleIncrement() {
  this.counter.value.increment();
}
```

```html
<section class="slds-p-around_small">
  <lightning-button label="Increment" onclick={handleIncrement}></lightning-button>
</section>
```

See a later section for the complete example.

## State Manager Considerations

State managers must not rely on DOM-specific APIs or data — elements, events, and so on. They're intended to help you manage data in your application. Interactions with the DOM belong in components.

## State Manager Example

This example is an expanded version of the counter state manager used in [Syntax Introduction: A Simple Counter](/docs/platform/lwc/guide/state-management-define-syntax.md). While still simple, it illustrates all three state manager implementation functions, and how to interact with the state manager from a component's user interface.

:::note
This example puts the `counterManager` state manager in a supplemental JavaScript file, separate from the `simpleCounter` component. While easy to use, it's not a best practice for a state manager you intend to share across many components — which is much of the point of state managers. The better way to define a state manager is in an [API module component](/docs/platform/lwc/guide/js-share-code.md). See [Share a State Manager Across Components](/docs/platform/lwc/guide/state-management-example-fromcontext.md) for an example.
:::

```javascript
// c/simpleCounter/counterManager.js
import { defineState } from "@lwc/state";

// Use the `defineState` function to define the values
// and actions your state manager provides
const counterManager = defineState(
  // This anonymous JavaScript function is the implementation
  // for a state manager instance.
  // `atom`, `computed`, and `setAtom` are state management functions
  // available in the context of `defineState`.

  // Your state manager can accept any number of arguments to define
  // its initial state. Here, this state manager can accept one argument
  // `initialValue` to set the beginning counter value, or use a
  // default value of zero.
  ({ atom, computed, setAtom }, initialValue = 0) => {
    // Create the counter, the state for this state manager.
    // An `atom` represents a single, reactive piece of data.
    // Changes to an atom trigger updates in components or
    // re-computation of derived values.
    const count = atom(initialValue);

    // Create computed (derived) value
    const doubleCount = computed([count], (countValue) => countValue * 2);

    // Create an action modify the state by incrementing it
    const increment = () => {
      setAtom(count, count.value + 1);
    };

    // Create an action that directly sets a new value for the `count` atom
    const setCount = (newValue) => {
      setAtom(count, newValue);
    };

    // Return an object that defines the public API of counterManager
    return {
      count, // the counter value
      doubleCount, // a computed, dependent value
      increment, // an action to increment the counter value by +1
      setCount, // an action to set the counter to an arbitrary value
    };
  },
);
export default counterManager;
```

```javascript
// c/simpleCounter/simpleCounter.js
import { LightningElement } from "lwc";
import counterManager from "./counterManager";

export default class SimpleCounter extends LightningElement {
  counter = counterManager();

  handleIncrement() {
    this.counter.value.increment();
  }

  handleSetCount() {
    this.counter.value.setCount(Number(this.refs.newValue.value));
  }

  get stateDump() {
    return JSON.stringify(this.counter.value, null, 2);
  }
}
```

```html
<!-- c/simpleCounter/simpleCounter.html -->
<template>
  <lightning-card title="Example: Simple Counter">
    <section class="slds-p-around_small">
      <p>Count: {counter.value.count}</p>
      <p>Doubled: {counter.value.doubleCount}</p>
    </section>

    <section class="slds-p-around_small">
      <lightning-button label="Increment" onclick={handleIncrement}></lightning-button>
    </section>

    <section class="slds-p-around_small">
      <lightning-input
        type="text"
        label="Counter"
        value={counter.value.count}
        lwc:ref="newValue"
      ></lightning-input>
      <lightning-button label="Set Counter" onclick={handleSetCount}></lightning-button>
    </section>

    <section class="slds-p-around_small">
      <hr />
      <textarea rows="10" cols="40">{stateDump}</textarea>
      <hr />
    </section>
  </lightning-card>
</template>
```
