I'm trying to implement a POC for a horizontally scrollable section on a project. I have 3 h3s next to each other above the horizontally scrollable section, the h3s should correspond to the individual sub-sections in the horizontal bit.
I am using react-intersection-observer to create refs to the sub-sections to be able to scroll to them when a user clicks on one of the h3s. The state is being set correctly, and in React Dev Tools I can see that the useInView hooks are being set correctly and also show the s as refs. However, when I try to access refOne.current anywhere, it comes back undefined. I'm explicitly using useLayoutEffect here to wait for all DOM nodes to be fully painted, but still refOne.current is undefined.
import React, { useState, useLayoutEffect } from 'react';
import { useInView } from 'react-intersection-observer';
import classNames from 'classnames';
import classes from './Projects.module.css';
const Projects = () => {
const [activeState, setActiveState] = useState('one');
let [refOne, inViewOne, entryOne] = useInView({
threshold: 1,
});
let [refTwo, inViewTwo, entryTwo] = useInView({
threshold: 1,
});
let [refThree, inViewThree, entryThree] = useInView({
threshold: 1,
});
useLayoutEffect(() => {
console.log(refOne.current) // comes back undefined
checkAndScroll(activeState);
}, [activeState]);
const setActiveHeading = (id) => {
setActiveState(id);
};
let oneClasses = classNames(classes.heading, {
[classes.activeHeading]: activeState === 'one',
});
let twoClasses = classNames(classes.heading, {
[classes.activeHeading]: activeState === 'two',
});
let threeClasses = classNames(classes.heading, {
[classes.activeHeading]: activeState === 'three',
});
const checkAndScroll = (id) => {
console.log(refOne.current) // comes back undefined
if (id === 'one' && !inViewOne) {
scrollToRef(refOne);
} else if (id === 'two' && !inViewTwo) {
scrollToRef(refTwo);
} else if (id === 'three' && !inViewThree) {
scrollToRef(refThree);
}
};
const scrollToRef = (ref) => {
console.log(refOne.current) // comes back undefined
if (ref && ref.current) {
ref.current.scrollIntoView();
}
};
return (
<>
<div className={classes.headingsContainer}>
<h3
className={oneClasses}
id={classes.headingOne}
onClick={() => setActiveHeading('one')}
>
One
</h3>
<h3
className={twoClasses}
id={classes.headingTwo}
onClick={() => setActiveHeading('two')}
>
Two
</h3>
<h3
className={threeClasses}
id={classes.headingThree}
onClick={() => setActiveHeading('three')}
>
Three
</h3>
</div>
<div className={classes.container}>
<div ref={refOne} className={classes.one} />
<div ref={refTwo} className={classes.two} />
<div ref={refThree} className={classes.three} />
</div>
</>
);
};
export default Projects;
I've been working on this for hours and I am at the end of my wits. Any help is much appreciated!
I'm explicitly using
useLayoutEffect
here to wait for all DOM nodes to be fully painted.React docs says this about
useLayoutEffect
.Have you tried
useEffect
instead ofuseLayoutEffect
?