-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ai/rsc components streamed through createStreamableUI are mounted multiple times when updating the ui node (update/done) #1257
Comments
Yes this is something related to |
Hi! Thanks for the clarification! I just wanted to point out that I am not using the |
In the posted example you can work around the mentioned suspense issue (i.e. the whole promise chain is replayed when the fallback is replaced with the children) by skipping the (async () => {
await sleep(50);
const textNode = createStreamableValue("");
- ui.update(<AssistantMessageWithStreamableValue content={textNode.value} />);
+ ui.done(<AssistantMessageWithStreamableValue content={textNode.value} />);
for await (const token of generateTokens(text)) {
textNode.update(token);
}
textNode.done();
- ui.done();
})(); |
I'm currently having a hard time working around this issue. I'm currently developing a shopping assistant for a work project. I want to provide some feedback in the UI when some products are added to the cart. Here I post an example of the code: completion.onEvent("add_products_to_cart", async (data) => {
let streamableCart:
| ReturnType<typeof createStreamableValue<Product>>
| undefined;
if (data.state === "START" || !streamableCart) {
streamableCart = createStreamableValue<Product>();
} else {
const { products } = data;
const product = products[Object.keys(products)[0]][0];
if (product) {
ui.update(
<>
<EventMessage>
{Object.keys(products).length} prodotti aggiunti al carrello
</EventMessage>
<AddToCart products={streamableCart.value} />
</>,
);
streamableCart.done(product);
}
}
}); And for the export function AddToCart({
products,
}: {
products: StreamableValue<Product>;
}) {
const { addToCart } = useShoppingCartActions();
useEffect(() => {
(async () => {
let productsToAdd: Product[] = [];
for await (const product of readStreamableValue(products)) {
if (product) {
productsToAdd.push(product);
}
}
if (productsToAdd.length > 0) {
console.log({ productsToAdd });
addToCart(productsToAdd);
}
})();
}, [products]);
return null;
} The problem I have is that products are added multiple times because the component is mounted multiple times. I haven't found a way to get around this and it's kinda blocking us |
this is a pretty big issue when using client components |
Description
I was reading through the https://chat.vercel.ai/ github example and in particular I found this useStreamableText hook. I report the implementation here for clarity:
When I used that hook in my project like in the following example:
I noticed the UI flashing during the last part of the stream. I checked directly on https://chat.vercel.ai/ and I noticed the same behaviour.
I tried printing to console
rawContent
and I noticed that just before the last delta received, rawContent becomes an empty string""
.I ended up figuring out that the actual
<AssistantMessage />
component is mounting mutiple times and it happens whenever the ui node is updated or when thedone
function is called and causing that flashing issue in my code. I made a reproduction here. Also not sure why in the codesanbox preview isn't really noticeable, but if you try looking at the preview in a new tab like here, you can see the issue more clearly.This happens on:
The text was updated successfully, but these errors were encountered: