Skip to content

Commit 0bfd418

Browse files
docs: add flushSync Troubleshooting section (#7978)
* docs: add flushSync Troubleshooting section * Update src/content/reference/react-dom/flushSync.md * oops * Apply suggestions from code review * formatting and pitfall --------- Co-authored-by: Ricky <[email protected]> Co-authored-by: Rick Hanlon <[email protected]>
1 parent 4d3d495 commit 0bfd418

File tree

1 file changed

+72
-0
lines changed

1 file changed

+72
-0
lines changed

src/content/reference/react-dom/flushSync.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,75 @@ Without `flushSync`, the print dialog will display `isPrinting` as "no". This is
131131
Most of the time, `flushSync` can be avoided, so use `flushSync` as a last resort.
132132

133133
</Pitfall>
134+
135+
---
136+
137+
## Troubleshooting {/*troubleshooting*/}
138+
139+
### I'm getting an error: "flushSync was called from inside a lifecycle method" {/*im-getting-an-error-flushsync-was-called-from-inside-a-lifecycle-method*/}
140+
141+
142+
React cannot `flushSync` in the middle of a render. If you do, it will noop and warn:
143+
144+
<ConsoleBlock level="error">
145+
146+
Warning: flushSync was called from inside a lifecycle method. React cannot flush when React is already rendering. Consider moving this call to a scheduler task or micro task.
147+
148+
</ConsoleBlock>
149+
150+
This includes calling `flushSync` inside:
151+
152+
- rendering a component.
153+
- `useLayoutEffect` or `useEffect` hooks.
154+
- Class component lifecycle methods.
155+
156+
For example, calling `flushSync` in an Effect will noop and warn:
157+
158+
```js
159+
import { useEffect } from 'react';
160+
import { flushSync } from 'react-dom';
161+
162+
function MyComponent() {
163+
useEffect(() => {
164+
// 🚩 Wrong: calling flushSync inside an effect
165+
flushSync(() => {
166+
setSomething(newValue);
167+
});
168+
}, []);
169+
170+
return <div>{/* ... */}</div>;
171+
}
172+
```
173+
174+
To fix this, you usually want to move the `flushSync` call to an event:
175+
176+
```js
177+
function handleClick() {
178+
// ✅ Correct: flushSync in event handlers is safe
179+
flushSync(() => {
180+
setSomething(newValue);
181+
});
182+
}
183+
```
184+
185+
186+
If it's difficult to move to an event, you can defer `flushSync` in a microtask:
187+
188+
```js {3,7}
189+
useEffect(() => {
190+
// ✅ Correct: defer flushSync to a microtask
191+
queueMicrotask(() => {
192+
flushSync(() => {
193+
setSomething(newValue);
194+
});
195+
});
196+
}, []);
197+
```
198+
199+
This will allow the current render to finish and schedule another syncronous render to flush the updates.
200+
201+
<Pitfall>
202+
203+
`flushSync` can significantly hurt performance, but this particular pattern is even worse for performance. Exhaust all other options before calling `flushSync` in a microtask as an escape hatch.
204+
205+
</Pitfall>

0 commit comments

Comments
 (0)