npm package: @nicolaferraro/realtime-sdk-react
Description: React hooks for Redpanda Realtime SDK
Latest version: 0.1.0

# Redpanda Realtime SDK - React

React hooks for [Redpanda Realtime SDK](../realtime-sdk).

## Installation

```bash
npm install @nicolaferraro/realtime-sdk-react
```

## Usage

### Basic Example (Default Reducer)

The default reducer accumulates data into an array:

```tsx
import { useChannel } from '@nicolaferraro/realtime-sdk-react';

interface ChatMessage {
  text: string;
  username: string;
}

function ChatRoom() {
  const { subChannel: messages, pubChannel } = useChannel<ChatMessage>('chat-room');

  const sendMessage = async () => {
    await pubChannel({ text: 'Hello!', username: 'Alice' });
  };

  return (
    <div>
      {messages.map((msg, i) => (
        <div key={i}>
          {msg.username}: {msg.text}
        </div>
      ))}
      <button onClick={sendMessage}>Send</button>
    </div>
  );
}
```

### Custom Reducer

Use a custom reducer to manage state differently:

```tsx
function Counter() {
  const { subChannel: count, pubChannel } = useChannel<number, number>(
    'counter',
    [
      0,                           // Initial state
      (state, value) => state + value  // Reducer function
    ]
  );

  return (
    <div>
      <div>Count: {count}</div>
      <button onClick={() => pubChannel(1)}>+1</button>
    </div>
  );
}
```

### With Error Handling

```tsx
function MyComponent() {
  const { subChannel, pubChannel, error } = useChannel<Message>('my-channel');

  return (
    <div>
      {error && <div>Error: {error.message}</div>}
      {/* ... */}
    </div>
  );
}
```

### With Custom Client

```tsx
import { Redpanda } from '@nicolaferraro/realtime-sdk';

const client = new Redpanda('https://api.example.com');

function MyComponent() {
  const { subChannel, pubChannel } = useChannel(
    'my-channel',
    undefined, // Use default reducer
    {
      client,
      onError: (err) => console.error(err),
    }
  );

  // ...
}
```

## API

### `useChannel<T, S>(channelName, reducer?, options?)`

React hook for interacting with a channel with reducer pattern.

#### Parameters

- `channelName: string` - The name of the channel
- `reducer?: [S, (state: S, data: T) => S]` - Optional reducer tuple (defaults to array accumulation)
- `options?: UseChannelOptions` - Configuration options

#### Reducer

The reducer is a tuple of `[initialState, reducerFunction]`:

```typescript
[
  initialState,          // Initial value
  (state, data) => newState  // Reducer function
]
```

The reducer function receives:
- `state: S` - The current state
- `data: T` - The received data payload (not including the key)

**Default Reducer:** If no reducer is provided, data is accumulated into an array `T[]`.

#### Options

```typescript
interface UseChannelOptions {
  client?: Redpanda;                // Custom client instance
  onError?: (error: Error) => void; // Error handler
}
```

To configure the base URL, create a custom Redpanda client:

```tsx
const client = new Redpanda('https://api.example.com');
const { subChannel, pubChannel } = useChannel('channel', undefined, { client });
```

#### Returns

```typescript
{
  subChannel: S;                           // Accumulated state
  pubChannel: (data: T) => Promise<void>;  // Publish function
  error?: Error | null;                    // Last error (optional)
}
```

You can destructure only what you need:

```tsx
// Just the data
const { subChannel, pubChannel } = useChannel('channel');

// Include error handling
const { subChannel, pubChannel, error } = useChannel('channel');
```

## Features

- Reducer pattern for flexible state management
- Default array accumulation (no reducer needed)
- Keys handled automatically by the SDK (empty string used for publish)
- Automatic connection management
- Automatic reconnection with exponential backoff
- Stream resumption from last received key
- TypeScript support with generics
- React lifecycle integration (cleanup on unmount)
- Error handling with optional error callback