Я создаю приложение, которое в значительной степени зависит от анимации, и у меня возникают проблемы при работе с динамическими ссылками и пользовательскими хуками.
Итак, у меня есть собственный хук, который добавляет прослушиватель событий щелчка, обрабатывает анимацию и возвращает ссылку.
const usePageChange = () => {
const node = useRef(null);
const tl = useMemo(() => gsap.timeline({ paused: true }), []);
useEffect(() => {
// Set GSAP timeline
// omited for the sake of brevety
return () => {
tl.kill();
};
}, []);
useEffect(() => {
const set = (ev) => {
ev.preventDefault();
tl.play();
};
const { current } = node;
current.addEventListener('click', set);
return () => {
current.removeEventListener('click', set);
};
}, [tl]);
return node;
};
Это отлично работает для refs, которые не являются динамическими:
const Home = () => {
const elementRef = usePageChange();
return (
<div className='slides'>
<img
alt='some alt'
src='/public/someimage.jpg'
ref = {elementRef}
/>
</div>
);
};
Но я не смог найти способ сделать это с динамическим refs, не нарушая Правила хуков.
Это то, что я пробовал (упрощенно), но, очевидно, это неправильно. React Hook нельзя вызвать внутри обратного вызова: useRef(projects.map(() => usePageChange()));
const Home = () => {
const projects = useSelector((state) => state.projects.data);
const elementsRef = useRef(projects.map(() => usePageChange()));
return (
<div className='slides'>
{projects.map((project, i) => (
<img
alt = {`${project.image_alt}`}
src = {`/public/${project.image_path}`}
ref = {elementsRef[i]}
/>
))}
</div>
);
};
Что мне действительно нужно, так это способ каким-то образом перебирать длину проектов и динамически вызывать хук usePageChange.
На данный момент я не знаю, лучше ли просто добавить событие клика непосредственно к каждому динамическому элементу и обрабатывать анимацию внутри компонента.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Для чего-то подобного было бы более разумно задавать состояние каждого элемента списка, а не пытаться поддерживать какой-то массив дочерних состояний в родительском компоненте.
const ProjectListItem = ({ project }) => {
const elementRef = usePageChange();
return (
<img
alt = {`${project.image_alt}`}
src = {`/public/${project.image_path}`}
ref = {elementRef}
/>
);
}
const Home = () => {
const projects = ...;
return (
<div className='slides'>
{projects.map(project => (
<ProjectListItem project = {project} />
))}
</div>
);
};
Если это не работает для вас, вы можете попробовать форму обратного вызова реквизита ref:
const usePageChange = () => {
const [node, setNode] = useState(null);
// ...
return { node, setNode };
};
const ProjectListItem = ({ project }) => {
const { setNode } = usePageChange();
return (
<img
alt = {`${project.image_alt}`}
src = {`/public/${project.image_path}`}
ref = {setNode}
/>
);
}
Гораздо разумнее обрабатывать его на отдельных компонентах. Спасибо за понимание и разъяснения!