# @autoSubscribe

The `@autoSubscribe` decorator automatically detects which publishers are accessed within a method and subscribes to them. When any of these publishers change, the method is automatically re-executed.

## Principle

This decorator wraps a method to track which publishers are accessed during its execution. It then subscribes to all accessed publishers, and when any of them change, the method is re-executed. This provides automatic reactivity without manually managing subscriptions.

## Usage

### Import

<sonic-code language="typescript">
  <template>
import { autoSubscribe } from "@supersoniks/concorde/decorators";
  </template>
</sonic-code>

### Basic example


<sonic-code language="typescript">
<template>
@customElement("demo-auto-subscribe")
export class DemoAutoSubscribe extends LitElement {
  static styles = [tailwind];
  //
  @state() displayText: string = "";
  @state() computedValue: number = 0;
  //
  @autoSubscribe()
  updateDisplay() {
    const value1 = PublisherManager.get("autoValue1").get() || 0;
    const value2 = PublisherManager.get("autoValue2").get() || 0;
    this.computedValue = value1 + value2;
    this.displayText = `${value1} + ${value2} = ${this.computedValue}`;
  }
  //
  render() {
    return html`
      <p><strong>${this.displayText}</strong></p>
      <div>
        <sonic-button @click=${() => this.randomizeValue("autoValue1")}>
          Randomize Value 1
        </sonic-button>
        <sonic-button @click=${() => this.randomizeValue("autoValue2")}>
          Randomize Value 2
        </sonic-button>
      </div>
    `;
  }
  //
  randomizeValue(publisherId: string) {
    const value = PublisherManager.get(publisherId);
    value.set(Math.floor(Math.random() * 100));
  }
}
</template>
</sonic-code>


<sonic-code >
  <template>
    <demo-auto-subscribe></demo-auto-subscribe>
  </template>
</sonic-code>

### Example with render method

<sonic-code language="typescript">
  <template>
@customElement("reactive-view")
export class ReactiveView extends LitElement {
  @autoSubscribe()
  render() {
    const data = PublisherManager.get("myData");
    const config = PublisherManager.get("config");
    //
    // This render method will be automatically re-executed
    // when myData or config change
    const value = data.get()?.value || 0;
    const multiplier = config.get()?.multiplier || 1;
    //
    return html`
      <div>
        <h1>Result: ${value * multiplier}</h1>
        <p>Value: ${value}</p>
        <p>Multiplier: ${multiplier}</p>
      </div>
    `;
  }
}
  </template>
</sonic-code>

## How it works

1. **First execution**: When the method is called, `PublisherManager.collectModifiedPublisher()` is used to track which publishers are accessed
2. **Subscription**: After execution, the decorator subscribes to all detected publishers
3. **Re-execution**: When any subscribed publisher changes, the method is automatically called again
4. **Cleanup**: On `disconnectedCallback`, all subscriptions are automatically removed

## Behavior

- The method is automatically called on `connectedCallback`
- The method is re-executed whenever any accessed publisher changes
- Subscriptions are managed automatically (no manual cleanup needed)
- Only publishers accessed during method execution are subscribed to
- The decorator uses `queueMicrotask` to batch multiple updates and avoid unnecessary re-renders

## Use cases

This decorator is particularly useful for:

- **Reactive rendering** where the render method depends on multiple publishers
- **Data transformation** that needs to update when source data changes
- **Computed properties** that depend on multiple data sources
- **Automatic synchronization** between publishers and component state

## Complete example

<sonic-code language="typescript">
  <template>
import { html, LitElement } from "lit";
import { customElement } from "lit/decorators.js";
import { autoSubscribe } from "@supersoniks/concorde/decorators";
import { PublisherManager } from "@supersoniks/concorde/core/utils/PublisherProxy";
//
@customElement("shopping-cart")
export class ShoppingCart extends LitElement {
  items: any[] = [];
  total: number = 0;
  discount: number = 0;
  //
  @autoSubscribe()
  calculateTotal() {
    const cart = PublisherManager.get("cart");
    const promo = PublisherManager.get("promo");
    //
    // Access cart items
    this.items = cart.items.get() || [];
    //
    // Access promo code
    const promoCode = promo.code.get() || "";
    const discountPercent = promoCode === "SAVE10" ? 0.1 : 0;
    //
    // Calculate totals
    const subtotal = this.items.reduce((sum, item) => 
      sum + (item.price * item.quantity), 0
    );
    this.discount = subtotal * discountPercent;
    this.total = subtotal - this.discount;
    //
    this.requestUpdate();
  }
  //
  connectedCallback() {
    super.connectedCallback();
    this.calculateTotal();
  }
  //
  render() {
    return html`
      <div class="cart">
        <h2>Shopping Cart</h2>
        ${this.items.map(item => html`
          <div>${item.name} x${item.quantity} - ${item.price}€</div>
        `)}
        <div class="total">
          <p>Subtotal: ${this.total + this.discount}€</p>
          <p>Discount: -${this.discount}€</p>
          <p><strong>Total: ${this.total}€</strong></p>
        </div>
      </div>
    `;
  }
}
//
// When you update the publishers, calculateTotal is automatically called:
const cart = PublisherManager.get("cart");
cart.items.set([
  { name: "Product 1", price: 10, quantity: 2 },
  { name: "Product 2", price: 15, quantity: 1 }
]);
//
const promo = PublisherManager.get("promo");
promo.code.set("SAVE10");
// calculateTotal will be automatically called and the UI will update
  </template>
</sonic-code>

## Notes

- This decorator works with any component that has `connectedCallback` and `disconnectedCallback` methods (such as `LitElement` or components extending `Subscriber`)
- The method is called automatically on `connectedCallback`
- Remember to call `this.requestUpdate()` if you're updating component properties
- The decorator uses debouncing via `queueMicrotask` to prevent excessive re-executions
- For more information about publishers, see the documentation on [Sharing data](#docs/_getting-started/pubsub.md/pubsub)

