React: обрабатывать динамические ссылки с помощью пользовательского хука

Я создаю приложение, которое в значительной степени зависит от анимации, и у меня возникают проблемы при работе с динамическими ссылками и пользовательскими хуками.

Итак, у меня есть собственный хук, который добавляет прослушиватель событий щелчка, обрабатывает анимацию и возвращает ссылку.

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.

На данный момент я не знаю, лучше ли просто добавить событие клика непосредственно к каждому динамическому элементу и обрабатывать анимацию внутри компонента.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
352
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для чего-то подобного было бы более разумно задавать состояние каждого элемента списка, а не пытаться поддерживать какой-то массив дочерних состояний в родительском компоненте.

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

Гораздо разумнее обрабатывать его на отдельных компонентах. Спасибо за понимание и разъяснения!

ajmnz 17.12.2020 01:31

Другие вопросы по теме