Reputation: 1655
I have a simple react App codesandbox (fork).
I use react-horizontal-scrolling-menu for navigation.
So, now Menu scrolls. Anchor links work. If you scroll through the menu, the sections will scroll.
But If you scroll through the sections, the menu will not scroll and the active class of the menu will not switch.
<ScrollMenu
ref={this.scrollRef}
data={menu}
transition={+transition}
onUpdate={this.onUpdate}
onSelect={this.onSelect}
selected={selected}
translate={translate}
alignCenter={alignCenter}
scrollToSelected={true}
dragging={dragging}
clickWhenDrag={clickWhenDrag}
wheel={wheel}
/>
</div>
{list.map((category) => (
<div
key={category.name}
id={`${category.name.replace(/\s+/g, "")}`}
className="section mb-4"
>
<h2>
{category.name} {selected}
</h2>
</div>
))}
Question: How, when scrolling through sections, add the active class of the menu and scroll the menu to the active class?
Upvotes: 2
Views: 2337
Reputation: 202618
I had to implement componentDidMount
and componentWillUnmount
and move the wheel event add/remove event listener in order to make your codesandbox useable. It was adding a new wheel handler on each update and quickly became unusable, very laggy.
You can use the Intersection Observer API to observe (spy) when the sections come into view and set the selected
state using the target element's id
attribute.
Create an array of element refs
elmentRefs = list.map(React.createRef);
Create the observers
createObservers = () => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
this.setState({ selected: entry.target.id });
}
});
},
{ threshold: 1.0 } // <-- section fully in view
);
this.elmentRefs.forEach(({ current }) => observer.observe(current));
};
...
componentDidMount() {
this.createObservers();
...
}
Attach the refs to the sections
{list.map((category, i) => (
<div
ref={this.elmentRefs[i]} // <-- attach element refs
key={category.name}
id={`${category.name.replace(/\s+/g, "")}`}
className="section mb-4"
>
<h2>
{category.name} {selected}
</h2>
</div>
))}
Upvotes: 1