I have 2 files
Home.jsx
import React, { useState, useEffect } from 'react';
import './Home.css';
const HomePage = () => {
const [visibleSections, setVisibleSections] = useState([]);
useEffect(() => {
const sections = ['header', 'description', 'button', 'footer'];
let index = 0;
const intervalId = setInterval(() => {
if (index < sections.length) {
setVisibleSections(prev => [...prev, sections[index]]);
index++;
} else {
clearInterval(intervalId);
}
}, 1000); // Delay of 1 second between each section
return () => clearInterval(intervalId);
}, []);
return (
<div className="home-page">
<header className={`section ${visibleSections.includes('header') ? 'visible' : ''}`}>
<h1>Welcome to Chess Play</h1>
</header>
<div className={`section description ${visibleSections.includes('description') ? 'visible' : ''}`}>
<p>
Experience the classic game of chess with our interactive platform. Whether you're a beginner or a seasoned player, our site offers a variety of features to enhance your chess skills.
</p>
</div>
<main className={`section main-content ${visibleSections.includes('button') ? 'visible' : ''}`}>
<button
className="play-button"
onClick={() => alert('Start Playing!')}
>
Start Playing
</button>
</main>
<footer className={`section ${visibleSections.includes('footer') ? 'visible' : ''}`}>
<p>© 2023 Chess Play. All rights reserved.</p>
</footer>
</div>
);
};
export default HomePage;
Home.css
.home-page {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
text-align: center;
}
.section {
margin-bottom: 20px;
transition: opacity 0.5s ease-out, transform 0.5s ease-out;
}
.section:not(.visible) {
opacity: 0;
transform: translateY(20px);
pointer-events: none;
}
.section.visible {
opacity: 1;
transform: translateY(0);
pointer-events: auto;
}
header h1 {
font-size: 2.5em;
margin-bottom: 20px;
}
.description {
max-width: 600px;
}
.play-button {
padding: 10px 20px;
font-size: 18px;
cursor: pointer;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
transition: background-color 0.3s;
}
.play-button:hover {
background-color: #45a049;
}
footer {
margin-top: 40px;
font-size: 0.9em;
color: #666;
}
The main goal is the content on the page appear one by one block(Header -> Description -> Button -> Footer). However, the Description does not render, but Its interactable(I can copy the text, but i cant see it)
That is how it looks like after all animations:
enter image description here
As you can see, the 2 block is not there.
Please, help me. Where is my mistake?
I tried play with tags and css but it did not work
2
Answers
As in your comment, if you just want to show all the sections, remove the state management of visible sections, the useEffect and these
${visibleSections.includes('header') ? 'visible' : ''}
Something like this should do it…
Your problem relates to closures and the async nature of setState updates.
Firstly, to fix the issue all you need to do is create another variable that is not enclosed by the updater function in
setVisibleSections
:Playground Link
So the problem probably happens because the arrow function:
(prev) => [...prev, sections[index]]
has closed over the variableindex
. And, hence it has access to the most updated value ofindex
.Now the sequence of events is this:
First iteration of the interval : index is 0,
setVisibleSections
is called. Its callback is also called (suprisingly) andindex
is increased to 1.Now second time,
index
is 1, andsetVisibleSections
is called but its callback is not called immediately. Instead index is increased to 2 first. And now the callback is called, and it uses the updated the value of 2.This React behaviour is peculiar but that is how it is. As can be seen in the playground. React Docs clearly mentions that updates from setState can be made async to the UI, and that is what happens in this case. But I do not see any mention as to if the callback would be called async or immediately so this might still be expected behaviour.
The code change above does not fix the ordering behavior, it only changes the code enough such that the behaviour does not cause an issue for you.
PS: Also, you can remove the index from updater function and just do
setVisibleSections((prev) => [...prev, sections[prev.length]]);