Chilarai has a great answer! (Maybe due to time of answer and now having more documentation) I do not agree with the idea of using it very sparingly. As a lot of the time it will stop the need for an extra unneeded useEffect
(It is also against how Dan suggests to use useEffect https://twitter.com/dan_abramov/status/1501737272999301121).
Here is a great example of what it achieves based on Dan Abramov's code:
The requirement for this code is an Auto-scroll on new message (I use this code currently and it is very effective).
Before, in this example we are unable to scroll after setMessages as the DOM will not be rendered yet and a hook is needed.
export default function App() {
const [messages, setMessages] = useState([]);
useEffect(() => {
let socket = connect();
socket.onMessage((message) => {
setMessages((m) => [
...m,
message
])
});
return () => {
socket.disconnect();
};
}, [])
function scrollToLastMessage() {
// ...
}
// NOTE: In order to scroll without using flushSync a unneeded hook
useEffect(() => {
scrollToLastMessage();
}, [messages])
}
After, in this example the DOM is forced to be flush synced and then we can call in the order we wanted.
export default function App() {
const [messages, setMessages] = useState([]);
useEffect(() => {
let socket = connect();
function scrollToLastMessage() {
// ...
}
socket.onMessage((message) => {
flushSync(() => {
setMessages((m) => [
...m,
message
])
})
scrollToLastMessage();
});
return () => {
socket.disconnect();
};
}, [])
}
This code comes from Dan in this video https://www.youtube.com/watch?v=uqII0AOW1NM at 35:25
I would recommend watching that!
I would also highly recommend adding flushSync to your toolbelt!
flushSync
to flush data synchronously. – Hereat