To answer the question:
<Waypoint/>
won't help to achieve what you want, it is not used for that, it is in fact a component that you can put inside your jsx.
Works in all containers that can scroll, including the window.
when you scroll, you can think of it as a point that once reached, left, or changes position, the corresponding event is triggered.
the previous position when you enter this point is always "below" here, because you have put <Waypoint/>
at the end of the grid.
the event
object is not useful as well for what you want, if you check event.doccument
you will find the whole scrollable element and not the last displayed element on the screen.
event - the native scroll event that triggered the callback. May be missing if the callback wasn't triggered as the result of a scroll.
so it is usually used
to build features like lazy loading content, infinite scroll, scrollspies, or docking elements to the viewport on scroll.
Solution:
you can use three <Waypoint/>
each one before each section and a state to indicate which is the last waypoint entred (the order of the section displayed):
const [currentSection, setCurrentSection] = useState(1);
then create a useEffect
hook to run each time currentSection
is updated:
useEffect(() => {
console.log("current section is updated and this is its order ", currentSection);
// now you have the number indicates of the current section you can manage how to make your nav bar react to that
}, [currentSection]);
JSX:
<Box>
<Waypoint
onEnter={() => {
setCurrentSection(1);
}}
/>
<Grid
container
display={"flex"}
flexDirection={"column"}
minHeight={"100vh"}
justifyContent={"space-between"}
>
<Grid
item
flexGrow={1}
style={{ height: "800px", background: "red" }}
>
<div>section 1</div>
</Grid>
<Waypoint
onEnter={() => {
setCurrentSection(2);
}}
/>
<Grid
item
flexGrow={1}
style={{ height: "800px", background: "white" }}
>
<div>section 2</div>
</Grid>
<Waypoint
onEnter={() => {
setCurrentSection(3);
}}
/>
<Grid
item
flexGrow={1}
style={{ height: "800px", background: "green" }}
>
<div>section 3</div>
</Grid>
</Grid>
</Box>
Alternative (without waypoint):
I used to manage this with an event listener on scrolling and refs.
you want to give a ref
and an id
to each grid
section container, also a state to indicate which section is currently on the screen:
const firstRef = useRef();
const secondRef = useRef();
const ThirdRef = useRef();
const [currentSection, setCurrentSection] = useState();
when the component mounts we setCurrentSection
to the first section and set our event listener:
useEffect(() => {
setCurrentSection(firstRef.current);
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
the handleScroll
function will run each time you scroll and update the currentSection
state, but likely this will rerender the component only when currentSection
gets a new value :
const handleScroll = () => {
const scrollPosition = window.scrollY || document.documentElement.scrollTop;
const windowHeight = window.innerHeight;
const sectionPositions = [
firstRef.current,
secondRef.current,
ThirdRef.current
];
const currentSection = sectionPositions.find(
(section) =>
scrollPosition >= section.offsetTop &&
scrollPosition < section.offsetTop + windowHeight
);
if (currentSection) {
setCurrentSection(currentSection);
}
};
finally, we create a useEffect
hook that will be triggered each time the value of currentSection
is updated:
useEffect(() => {
if (currentSection) {
console.log("current section is updated and this is the id of the current one: ", currentSection.id);
// now you have the id of the current section you can manage how to make your nav bar react to that
}
}, [currentSection]);
Full example:
const Test = () => {
const firstRef = useRef();
const secondRef = useRef();
const ThirdRef = useRef();
const [currentSection, setCurrentSection] = useState();
const handleScroll = () => {
const scrollPosition = window.scrollY || document.documentElement.scrollTop;
const windowHeight = window.innerHeight;
const sectionPositions = [ firstRef.current, secondRef.current, ThirdRef.current ];
const currentSection = sectionPositions.find(
(section) =>
scrollPosition >= section.offsetTop && scrollPosition < section.offsetTop + windowHeight
);
if (currentSection) {
setCurrentSection(currentSection);
}
};
useEffect(() => {
setCurrentSection(firstRef.current);
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
useEffect(() => {
if (currentSection) {
console.log("current section is updated and this is the id of the current one: ", currentSection.id );
// now you have the id of the current section you can manage how to make your nav bar react to that
}
}, [currentSection]);
return (
<div className="App">
<Box>
<Grid
container
display={"flex"}
flexDirection={"column"}
minHeight={"100vh"}
justifyContent={"space-between"}
>
<Grid
id={1}
item
flexGrow={1}
style={{ height: "800px", background: "red" }}
ref={firstRef}
>
<div>section 1</div>
</Grid>
<Grid
id={2}
item
flexGrow={1}
style={{ height: "800px", background: "white" }}
ref={secondRef}
>
<div>section 2</div>
</Grid>
<Grid
id={3}
item
flexGrow={1}
style={{ height: "800px", background: "green" }}
ref={ThirdRef}
>
<div>section 3</div>
</Grid>
</Grid>
</Box>
</div>
);
};