React ref.current не определен в useLayoutEffect
Я пытаюсь реализовать POC для горизонтально прокручиваемого раздела в проекте. У меня 3 h3s рядом друг с другом над горизонтально прокручиваемым разделом, h3s должны соответствовать отдельным подразделам в горизонтальном бите.
Я использую реагировать-пересечение-наблюдатель, чтобы создавать ссылки на подразделы, чтобы иметь возможность прокручивать их, когда пользователь нажимает на один из h3s. Состояние устанавливается правильно, и в React Dev Tools я вижу, что хуки useInView устанавливаются правильно, а также отображают s как refs. Однако, когда я пытаюсь получить доступ к refOne.current где угодно, он возвращается undefined. Я явно использую useLayoutEffect здесь, чтобы дождаться, пока все узлы DOM будут полностью отрисованы, но refOne.current все еще не определен.
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;
Я работал над этим часами, и мне уже не до ума. Любая помощь высоко ценится!
2 ответа
Я наконец понял это, и это чертовски глупо.
Ловушка response-Crossction-Observer предоставляет ссылку, логическое значение inView и объект входа. Однако на самом деле реф.
Ссылок является функцией обратного вызова, которая не содержит текущее свойство (следовательно, не определенно). См. Комментарий создателя здесь: https://github.com/thebuilder/react-intersection-observer/issues/285
Вместо этого вам следует использовать возвращаемый объект ввода и получить доступ к целевому свойству. Если вы правильно назначили свои ссылки, entry.target будет содержать html-узел, которому вы назначили ссылку.
Я явно использую useLayoutEffect
здесь, чтобы ждать, пока все узлы DOM будут полностью окрашены.
Обновления запланированы внутри
useLayoutEffect
будут сброшены синхронно, прежде чем браузер сможет рисовать.
В React docs говорится об этомuseLayoutEffect
.
Попытался ли ты useEffect
вместо того useLayoutEffect
?