# Observer - Memorio

Observer lets you react to state changes. When a state key changes, your callback function runs.

## Installation

```bash
npm install memorio
```

```javascript
import 'memorio';
```

---

## Quick Examples

### Example 1: Basic Usage

```javascript
observer('state.counter', (newValue) => {
  console.debug('Counter is now:', newValue);
});

state.counter = 1;
// Output: "Counter is now: 1"

state.counter = 5;
// Output: "Counter is now: 5"
```

### Example 2: Intermediate

```javascript
// Observer with old value
observer('state.user', (newValue, oldValue) => {
  console.debug(`User changed from ${oldValue?.name} to ${newValue?.name}`);
});

state.user = { name: 'Mario' };
// Output: "User changed from undefined to Mario"

state.user = { name: 'Luigi' };
// Output: "User changed from Mario to Luigi"
```

### Example 3: Advanced

```javascript
// Multiple callbacks for same path
observer('state.data', [handler1, handler2]);

// List all observers
console.debug(observer.list);
// Output: [{ name: 'state.data', id: '...' }, ...]

// Remove specific observer
observer.remove('state.data');

// Remove all observers
observer.removeAll();

// Check if observer exists
if (observer.has('state.counter')) {
  console.debug('Observer exists for counter');
}
```

---

## Direct Values (Vanilla JS)

Observer supports direct state values, not just string paths:

```javascript
// Direct value - no string needed!
observer(state.counter, (newValue) => {
  console.debug('Counter:', newValue);
});

// Works with objects too
observer(state.user, (newValue) => {
  console.debug('User:', newValue?.name);
});

// Multiple callbacks as array
observer('state.data', [cb1, cb2, cb3]);
```

---

## API Reference

### observer(path, callback, option)

| Parameter | Type | Description |
|-----------|------|-------------|
| `path` | `string \| object` | State path (e.g., `'state.counter'`) or direct state value |
| `callback` | `function \| array` | Function(s) called on change. Can be a single function or array of functions |
| `option` | `boolean` | Listen continuously (default: `true`) |

### Callback Parameters

```javascript
observer('state.key', (newValue, oldValue) => {
  // newValue: the new value
  // oldValue: the previous value
});
```

### Properties

| Property | Type | Description |
|----------|------|-------------|
| `observer.list` | `Array` | Get all active observers |

### Methods

| Method | Parameters | Description |
|--------|------------|-------------|
| `observer.remove(name)` | `string` | Remove observer for specific path |
| `observer.removeAll()` | none | Remove all observers |
| `observer.has(name)` | `string` | Check if observer exists for path (returns boolean) |

---

## React Integration

### With useState

```javascript
const [count, setCount] = useState(0);

observer('state.counter', () => {
  setCount(state.counter);
});
```

### With useEffect

```javascript
useEffect(() => {
  const handleChange = (newVal) => {
    console.debug('Changed:', newVal);
  };

  observer('state.data', handleChange);

  // Cleanup
  return () => observer.remove('state.data');
}, []);
```

---

## How It Works

Observer subscribes to state changes via the Proxy's set trap. When `state.key = value` is called:
1. The Proxy intercepts the set
2. Fires all callbacks registered for that path
3. Callbacks receive newValue and oldValue

---

## Best Practices

1. Clean up observers in React `useEffect` return
2. Use specific paths: `'state.user.name'` not `'state'`
3. Remove observers when components unmount
4. Use `observer.removeAll()` on page navigation

---

## Common Patterns

### Form Validation

```javascript
observer('state.form.email', (email) => {
  const isValid = email.includes('@');
  state.form.isValid = isValid;
});
```

### Analytics

```javascript
observer('state.page', (page) => {
  analytics.track('page_view', { page });
});
```

### Auto-save

```javascript
observer('state.draft', (content) => {
  store.set('autosave', content);
});
```
