Skip to content
This repository has been archived by the owner on Dec 5, 2024. It is now read-only.

Warning: flushSync was called from inside a lifecycle method. #458

Open
catamphetamine opened this issue Jun 5, 2023 · 3 comments
Open

Comments

@catamphetamine
Copy link

I get the following warning in the console:

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.

The warning seems to originate from this flushSync() call:

ReactDOM.flushSync(() => {

The same issue was encountered in Mantine React component library. They've decided to migrate from react-popper to fix that in that issue.

@denisinvader
Copy link

Using Promise.resolve().then(popper.forceUpdate) instead of popper.forceUpdate() solves the issue as mentioned in salute-developers/plasma PR

@catamphetamine
Copy link
Author

So looks like the rationale for the suggested workaround is that react-popper's forceUpdate() function, calls flushSync() inside. Therefore, it shouldn't be called in a callback right after the component has re-rendered because that results in a second render right after the first one, and React doesn't like that, presumably for performance reasons. Spacing out those two renders in time via Promise.resolve() seems to fix the React warning.

@catamphetamine
Copy link
Author

catamphetamine commented Oct 21, 2023

I've tested the suggested Promise.resolve() approach and it doesn't really work and the warning is still being shown. What worked though is setTimeout(forceUpdate, 0). Not forget that the timeout should be "cleared" on component unmount.

const { styles, attributes, forceUpdate } = usePopper(...)
	
const updateTooltipPositionTimer = useRef()

// Update tooltip position.
if (updateTooltipPositionTimer.current) {
	clearTimeout(updateTooltipPositionTimer.current)
	updateTooltipPositionTimer.current = undefined
}
updateTooltipPositionTimer.current = setTimeout(() => {
	updateTooltipPositionTimer.current = undefined
	forceUpdate()
}, 0)

...

useEffect(() => {
	return () => {
		if (updateTooltipPositionTimer.current) {
			clearTimeout(updateTooltipPositionTimer.current)
			updateTooltipPositionTimer.current = undefined
		}
	}
}, [])

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants