Skip to content

fix(react): prevent double resume in React StrictMode#11509

Open
jacobwisniewski wants to merge 3 commits intovercel:mainfrom
jacobwisniewski:fix/use-chat-strict-mode-resume
Open

fix(react): prevent double resume in React StrictMode#11509
jacobwisniewski wants to merge 3 commits intovercel:mainfrom
jacobwisniewski:fix/use-chat-strict-mode-resume

Conversation

@jacobwisniewski
Copy link
Copy Markdown

@jacobwisniewski jacobwisniewski commented Jan 4, 2026

Background

When using useChat with resume: true, refreshing the page mid-stream causes duplicate stream requests because React StrictMode runs effects twice (mount → unmount → mount). The current implementation has no protection against this:

useEffect(() => {
  if (resume) {
    chatRef.current.resumeStream();
  }
}, [resume, chatRef]);

This leads to:

  • Duplicated/repeated text in the UI
  • Multiple concurrent stream consumers
  • Inconsistent message state
  • onData callbacks being called twice per server write

Summary

This PR adds a ref guard to prevent resumeStream() from being called twice when React StrictMode double-invokes effects during development.

Add a hasResumedRef that tracks whether resume has already been attempted:

const hasResumedRef = useRef(false);

useEffect(() => {
  if (resume && !hasResumedRef.current) {
    hasResumedRef.current = true;
    chatRef.current.resumeStream();
  }
}, [resume, chatRef]);

Testing

Added a test case that renders the component in <React.StrictMode> and verifies only one resume request is made despite effects running twice.

Related Issues

Fixes #9610

@ghost ghost added the ai/ui anything UI related label Jan 4, 2026
@jacobwisniewski jacobwisniewski force-pushed the fix/use-chat-strict-mode-resume branch 2 times, most recently from 763f0a4 to 7e31534 Compare January 5, 2026 00:23
Comment thread packages/react/src/use-chat.ui.test.tsx Outdated
@lgrammel
Copy link
Copy Markdown
Collaborator

lgrammel commented Jan 7, 2026

please add a patch changeset

@lgrammel
Copy link
Copy Markdown
Collaborator

lgrammel commented Jan 7, 2026

for future PRs please try to follow our PR description template

jacobwisniewski and others added 2 commits January 8, 2026 09:33
Add a ref guard to prevent resumeStream() from being called twice
when React StrictMode double-invokes effects during development.

This fixes an issue where refreshing the page mid-stream would cause
duplicate stream requests, leading to:
- Duplicated/repeated text in the UI
- Multiple concurrent stream consumers
- Inconsistent message state

The fix adds a hasResumedRef that tracks whether resume has already
been attempted, preventing the second invocation from making another
request.

Fixes vercel#9610
@jacobwisniewski jacobwisniewski force-pushed the fix/use-chat-strict-mode-resume branch from 7420ac1 to 806d9d4 Compare January 7, 2026 22:33
@jacobwisniewski
Copy link
Copy Markdown
Author

please add a patch changeset

Done!

for future PRs please try to follow our PR description template

Will do!

Comment on lines +113 to 120
const hasResumedRef = useRef(false);

useEffect(() => {
if (resume) {
if (resume && !hasResumedRef.current) {
hasResumedRef.current = true;
chatRef.current.resumeStream();
}
}, [resume, chatRef]);
Copy link
Copy Markdown
Collaborator

@lgrammel lgrammel Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the ref need to be reset to false? maybe i missing something here, want to make sure this works on the several resumes not just the 1st one

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai/ui anything UI related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

onData callback called twice per writer.write() when using resumable streams

2 participants