# useObserver - Memorio

> ⚛️ **React Only**: This is a React hook and only works within React components

useObserver is a React hook for observing state changes. It automatically subscribes to state changes and includes powerful auto-discovery features.

## Installation

```bash
npm install memorio
```

```javascript
import 'memorio';
```

---

## Quick Examples

### Example 1: Basic Usage

```javascript
import 'memorio';

function Counter() {
  // Direct values work! ✅
  useObserver(() => {
    console.debug('Counter changed:', state.counter);
  }, [state.counter]);

  return <div>{state.counter}</div>;
}
```

### Auto-Discovery (Magic Mode)

```javascript
// Pass your callback WITHOUT dependencies - it auto-discovers!
function MyComponent() {
  useObserver(() => {
    // This will automatically track ALL state properties used inside
    console.debug('Something changed:', state.user.name, state.items.length);
  });

  return <div>{state.user.name}</div>;
}
```

### Example 2: Intermediate

```javascript
function UserProfile() {
  const [localState, setLocalState] = useState(null);

  useObserver(() => {
    setLocalState(state.user);
  }, [state.user]);

  return <div>{localState?.name}</div>;
}
```

### Example 3: Advanced

```javascript
// Multiple watchers with array - works with direct values
function MultiWatch() {
  useObserver(() => {
    console.debug('A or B changed:', state.a, state.b);
  }, [state.a, state.b]); // Direct values work!
  
  return <div>{state.a} - {state.b}</div>;
}

// With string path (for store)
function StoreWatcher() {
  useObserver(() => {
    console.debug('Store changed');
  }, 'store.userPreferences');

  return <div />;
}
```
// With string path (for store)
function StoreWatcher() {
  useObserver(() => {
    console.debug('Store changed');
  }, 'store.userPreferences');

  return <div />;
}
```

---

## API Reference

### useObserver(callback, deps)

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `callback` | `function` | Function to run on change |
| `deps` | `function \| string \| array \| proxy` | State path(s) to watch. Supports: |
| | | - Direct values: `state.counter` |
| | | - String paths: `'state.counter'` |
| | | - Arrow functions: `() => state.counter` |
| | | - Arrays: `[state.a, state.b]` or `['state.a', 'state.b']` |
| | | - Optional chaining: `[state?.one]` |

### Primitive Values

Direct primitive values are now fully supported:

```javascript
// Direct values work with primitives ✅
useObserver(() => { console.debug('changed') }, [state.counter])

// Arrays of primitives work ✅
useObserver(() => { console.log(state.a, state.b) }, [state.a, state.b])

// Optional chaining works ✅
useObserver(() => { console.log(state?.one) }, [state?.one])

// Strings still work ✅
useObserver(() => { console.debug('changed') }, ['state.counter'])

// Functions still work ✅
useObserver(() => { console.debug('changed') }, [() => state.counter])
```

### Callback Parameters

```javascript
// Single value (no array needed)
useObserver(
  () => {
    console.debug('Changed:', state.key);
  }, state.key  // Single value works!
);

// Array of values
useObserver(
  () => {
    console.debug('Changed:', state.key);
  }, [state.key]  // Array also works!
);
```

### Auto-Discovery Mode

When `deps` is omitted, useObserver automatically discovers all state properties accessed inside the callback:

```javascript
// No deps needed - magic auto-discovery!
useObserver(() => {
  // Automatically tracks state.user, state.items, state.counter
  console.debug(state.user.name, state.items.length, state.counter);
},[]);
```

Returns a cleanup function:

## useObserver vs observer

| Feature | observer | useObserver |
| ------- | -------- | ----------- |
| Framework | Vanilla JS | React |
| Auto-cleanup | Manual | Auto |
| React lifecycle | No | Yes |

---

## Common Patterns

### Sync with useState (Recommended for Primitives)

```javascript
function CounterComponent() {
  // Sync memorio state with React state
  const [counter, setCounter] = useState(state.counter)
  
  // React useEffect works correctly with primitive values
  useEffect(() => {
    console.log('Counter changed:', counter)
  }, [counter])
  
  // Direct values now work with primitives!
  useObserver(() => {
    setCounter(state.counter)
  }, [state.counter])  // ✅ Works now!
  
  return (
    <div>
      <button onClick={() => { state.counter++ }}>Increment</button>
      <span>{counter}</span>
    </div>
  )
}
```

### Safe Access with Optional Chaining (Protection)

```javascript
// Optional chaining is supported - protects against errors
useObserver(() => {
  if (test?.one) {
    console.log(test.one)
  }
}, [test?.one])

// Works with objects
function SafeComponent() {
  const [test, setTest] = useState(state.test)
  
  useEffect(() => {
    if (test?.one) {
      console.log('test.one:', test.one)
    }
  }, [test?.one])
  
  useObserver(() => {
    if (state.test?.one) {
      setTest(state.test)
    }
  }, ['state.test.one'])
  
  return <div>{test?.one || 'Loading...'}</div>
}
```

### Multiple Watchers

```javascript
// Watch multiple properties with strings
useObserver(() => {
  console.log(state.a, state.b)
}, ['state.a', 'state.b'])

// Watch multiple properties with functions
useObserver(() => {
  console.log(state.a, state.b)
}, [() => state.a, () => state.b])

// Watch with auto-discovery
useObserver(() => {
  console.log(state.a, state.b) // Automatically tracks both
}, [])
```

---

## Best Practices

1. Always use in React components
2. Use auto-discovery for simpler code: `useObserver(() => { ... })`
3. No manual cleanup needed - returns cleanup function automatically
4. Use with state for reactive UI
5. Check console for auto-discovery logs
