File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -115,7 +115,6 @@ export function useSmoothText(
115115 revealedRef . current = content . length
116116 setRevealed ( content . length )
117117 }
118- prevIsStreamingRef . current = isStreaming
119118
120119 if (
121120 snapOnNonAppend &&
@@ -127,12 +126,21 @@ export function useSmoothText(
127126 revealedRef . current = content . length
128127 setRevealed ( content . length )
129128 }
130- prevContentRef . current = content
131129
132130 contentRef . current = content
133131
134132 const hasBacklog = effectiveRevealed < content . length
135133
134+ // Advance the previous-input trackers on commit, never during render. A concurrent render can be
135+ // started and then thrown away before it commits (interrupted by a higher-priority update); a
136+ // render-phase write persists on that discarded attempt, so the retried render would read a stale
137+ // `prev` and skip the snap. Updating them in a committed effect keeps `prev` in lockstep with the
138+ // render that actually committed, so the snap decision is identical across discarded attempts.
139+ useEffect ( ( ) => {
140+ prevContentRef . current = content
141+ prevIsStreamingRef . current = isStreaming
142+ } , [ content , isStreaming ] )
143+
136144 useEffect ( ( ) => {
137145 const run = ( ) => {
138146 timeoutRef . current = null
You can’t perform that action at this time.
0 commit comments