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

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

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

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.

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


person ajmnz    schedule 16.12.2020    source источник


Ответы (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}
    />
  );
}
person Aaron    schedule 17.12.2020
comment
Работать с ним на отдельных компонентах имеет гораздо больше смысла. Спасибо за понимание и разъяснения! - person ajmnz; 17.12.2020