first off I'm cloning Youtube for practice. I made handleSearch
event handler to get videos from the search keyword.
const App = ({ youtube }) => {
const [videos, setVideos] = useState([]);
const [selectedVideo, setSelectedVideo] = useState(null);
const [loading, setLoading] = useState(false);
const handleSearch = useCallback((q) => {
setLoading(true);
console.log("loading -> true"); // 1
setSelectedVideo(null);
console.log("selectedVideo -> null"); // 2
// 3 Component rendering
youtube.search(q).then((videos) => {
console.log("Before setVideos"); // 4
setVideos(videos.map((video) => ({ ...video, id: video.id.videoId })));
console.log("After setVideos"); // 5
setLoading(false);
console.log("loading -> false"); // 6
});
// 7 Component rendering
}, []);
return (
<>
{console.log("Component rendering")}
...
youtube
is a class that exists in another file - it can execute fetch
.
Anyway, I wrote 7 comments above about the moment when something is printed out on the console. (And my console below)
But I can't understand that first rendering (third printed one).
According to Dan Abramov's answer: https://stackoverflow.com/a/48610973/17356311,
The key to understanding this is that no matter how many setState() calls in how many components you do inside a React event handler, they will produce only a single re-render at the end of the event.
So if in your example we had an AJAX response handler instead of handleClick, each setState() would be processed immediately as it happens. In this case, yes, you would see an intermediate state:
setState
in event handlers are batched, but not in response handlers. right?
So if the console had printed out 1 -> 2 -> 4 -> Component rendering -> 5 -> 6 -> Component rendering, I would have understood why it rendered twice. But now the sequence is strange...
Why does this component render after setting selectedVideo
to null?