# State Management

State management is at the heart of Ignite-Element’s design. By integrating with state management libraries like **XState**, **Redux**, or **MobX**, Ignite-Element lets you decouple your component’s logic from its rendering, resulting in simple, reusable, and framework-agnostic components.

***

### Decoupling Logic from Rendering

A key pattern to follow when using Ignite-Element is to keep all application logic—state transitions, actions, and business rules—inside the state management library. Ignite-Element focuses solely on rendering the component based on the state and events provided by the library.

This separation of concerns offers several benefits:

* **Dumb Components**: Components become "dumb" or purely presentational, only concerned with rendering the current state and dispatching events.
* **Reusability**: As long as the state management library handles the required state and actions, the same component can be reused across multiple frameworks or projects.
* **Maintainability**: Logic and rendering are clearly separated, making the codebase easier to understand and maintain.

***

### Example: Traffic Light

#### State Management (XState Example)

The traffic light’s state machine is defined:

* States for each light (red, yellow, green).
* Transitions between states on a `NEXT` event.
* A timer for automatically transitioning after a delay.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
import { createMachine } from "xstate";

const trafficLightMachine = createMachine({
  id: "trafficLight",
  initial: "red",
  states: {
    red: {
      after: { 5000: "green" }, // Transition to green after 5 seconds
      on: { NEXT: "green" },
    },
    green: {
      after: { 5000: "yellow" }, // Transition to yellow after 5 seconds
      on: { NEXT: "yellow" },
    },
    yellow: {
      after: { 3000: "red" }, // Transition to red after 3 seconds
      on: { NEXT: "red" },
    },
  },
});

export default trafficLightMachine;
```

{% endtab %}
{% endtabs %}

***

#### Component Rendering

Ignite-Element components use `state.value` to render the appropriate UI dynamically. This ensures the rendering logic is simple, scalable, and directly tied to the state machine.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
import { igniteCore } from "ignite-element";
import { html } from "lit-html"
import trafficLightMachine from "./trafficLightMachine";

const { shared } = igniteCore({
  adapter: "xstate",
  source: trafficLightMachine,
});

shared("traffic-light", (state, send) => {
  // Use state.value to set the color dynamically
  const color = state.value;

  return html`
    <div style="text-align: center;">
      <div
        style="height: 100px; width: 100px; margin: auto; border: 1px solid black; border-radius: 50%; background: ${color};"
      ></div>
      <button @click=${() => send({ type: "NEXT" })} style="margin-top: 20px;">
        Next
      </button>
    </div>
  `;
});

```

{% endtab %}
{% endtabs %}

***

### Why This Pattern Works

By keeping the logic in the state machine and using Ignite-Element purely for rendering:

* Components are framework-agnostic and easy to reuse.
* Logic is centralized in the state machine, making it easier to test and debug.
* The components remain "dumb," focused only on displaying the current state and triggering events.

***

### Best Practices

* **Centralize Logic in the State Machine**:\
  Use state management libraries to define all state transitions, actions, and context.
* **Simplify Component Rendering**:\
  Use `state.value` for conditional rendering to keep components readable and maintainable.
* **Ensure Reusability**:\
  You can reuse the same components in different projects or frameworks by decoupling logic from components.
