Skip to content
Docs
experimental_StreamingReactResponse

experimental_StreamingReactResponse

The experimental_StreamingReactResponse class allows you to stream React component responses.

đź’ˇ

The experimental_ prefix indicates that the API is not yet stable and may change in the future without a major version bump.

It is currently only implemented from ai/react's useChat hook.

experimental_StreamingReactResponse(res: ReadableStream, options?: ResponseOptions): Response

The experimental_StreamingReactResponse class is designed to facilitate streaming React responses in a server action environment. It can handle and stream both raw content and data payloads, including special UI payloads, through nested promises.

Parameters

res: ReadableStream

This parameter should be a ReadableStream, which encapsulates the HTTP response's content. It represents the stream from which the response is read and processed.

options?: {ui?: Function, data?: experimental_StreamData}

This optional parameter allows additional configurations for rendering React components and handling streamed data.

The options object can include:

  • ui?: (message: {content: string, data?: JSONValue[] | undefined}) => UINode | Promise<UINode>: A function that receives a message object with content and optional data fields. This function should return a React component (as UINode) for each chunk in the stream. The data attribute in the message is available when the data option is configured to include stream data.
  • data?: experimental_StreamData: An instance of experimental_StreamData used to process and stream data along with the response.

Returns

The method returns a Promise<ReactResponseRow>, which resolves to the next row of the React response. Each row contains a payload with UI components (ui), raw content (content), and a next property pointing to the subsequent row or null if it's the last row. This setup allows for continuous streaming and rendering of data in a React-based UI.

Example

Server-Side Implementation

This example highlights the usage of experimental_StreamingReactResponse specifically within a server action context in a Next.js environment. It is crucial to note that this functionality is only available when used in server actions. For more details on server actions, visit Next.js Documentation on Server Actions (opens in a new tab).

In this server-side script, the handler function interacts with the OpenAI API to process and stream chat completions. The responses are streamed using OpenAIStream and subsequently managed by experimental_StreamingReactResponse for dynamic React component rendering.

Server:

app/stream-react-response/action.tsx
'use server';
 
import OpenAI from 'openai';
import { OpenAIStream, experimental_StreamingReactResponse, Message } from 'ai';
 
const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY!,
});
 
export async function handler({ messages }: { messages: Message[] }) {
  // Request the OpenAI API for the response based on the prompt
  const response = await openai.chat.completions.create({
    model: 'gpt-3.5-turbo',
    stream: true,
    messages: messages as any,
  });
 
  // Convert the response into a friendly text-stream
  const stream = OpenAIStream(response);
 
  // Respond with the stream
  return new experimental_StreamingReactResponse(stream, {
    ui({ content }) {
      return (
        <div className="italic text-red-800">
          {content} Visit Next.js docs at{' '}
          <a
            href="https://nextjs.org/docs"
            target="_blank"
            className="underline"
          >
            https://nextjs.org/docs
          </a>
        </div>
      );
    },
  });
}

Client-Side Setup

On the client side, the useChat hook from ai/react is utilized to manage the chat interaction. The Chat component below renders the chat interface, including input forms and message displays. It dynamically integrates the server-side stream, displaying messages and UI elements as they are received.

app/stream-react-response/page.tsx
import { handler } from './action';
import { Chat } from './chat';
 
export const runtime = 'edge';
 
export default function Page() {
  return <Chat handler={handler} />;
}
app/stream-react-response/chat.tsx
'use client';
 
import { useChat } from 'ai/react';
 
export function Chat({ handler }: { handler: any }) {
  const { messages, input, handleInputChange, handleSubmit } = useChat({
    api: handler,
  });
 
  return (
    <div className="flex flex-col w-full max-w-md py-24 mx-auto stretch">
      <ul>
        {messages.map((m, index) => (
          <li key={index}>
            {m.role === 'user' ? 'User: ' : 'AI: '}
            {m.role === 'user' ? m.content : m.ui}
          </li>
        ))}
      </ul>
 
      <form onSubmit={handleSubmit}>
        <input
          className="fixed bottom-0 w-full max-w-md p-2 mb-8 border border-gray-300 rounded shadow-xl"
          placeholder="What is the weather in New York?"
          value={input}
          onChange={handleInputChange}
          autoFocus
        />
      </form>
    </div>
  );
}

© 2023 Vercel Inc.