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>
);
};