Есть TimelineLite играть только один раз на сайте Gatsby

#reactjs #gatsby #gsap #reach-router

#reactjs #gatsby #gsap #reach-маршрутизатор

Вопрос:

TimelineLite На моем сайте Gatsby настроена временная шкала для анимации моего hero раздела, когда пользователь переходит на страницу. Однако, если пользователь нажимает на ссылку на текущую страницу, т.Е. Если пользователь находится на главной странице и нажимает на ссылку на домашнюю страницу, это перезагружает страницу и запускает временную шкалу для повторного запуска. Есть ли способ убедиться, что моя текущая ссылка будет неактивной в Gatsby?

Hero.tsx

 import React, { useEffect, useRef, useState } from 'react';

import css from 'classnames';
import { ArrowButton } from 'components/arrow-button/ArrowButton';
import { HeadingReveal } from 'components/heading-reveal/HeadingReveal';
import { gsap, Power2, TimelineLite } from 'gsap';
import { RichText } from 'prismic-reactjs';
import htmlSerializer from 'utils/htmlSerializer';
import { linkResolver } from 'utils/linkResolver';

import s from './Hero.scss';

gsap.registerPlugin(TimelineLite, Power2);

export const Hero = ({ slice }: any) => {
  const linkType = slice.primary.link._linkType;
  const buttonLink =
    linkType === 'Link.document' ? slice.primary.link._meta : slice.primary.link.url;

  const theme = slice.primary.theme;
  const image = slice.primary.image;

  const contentRef = useRef(null);
  const headingRef = useRef(null);
  const copyRef = useRef(null);
  const buttonRef = useRef(null);

  const [tl] = useState(new TimelineLite({ delay: 0.5 }));

  useEffect(() => {
    tl.to(contentRef.current, { css: { visibility: 'visible' }, duration: 0 })
      .from(headingRef.current, { y: 65, ease: Power2.easeOut, duration: 1 })
      .from(copyRef.current, { opacity: 0, y: 20, ease: Power2.easeOut, duration: 1 }, 0.5)
      .from(buttonRef.current, { opacity: 0, y: 10, ease: Power2.easeOut, duration: 1 }, 1);
  }, [tl]);

  return (
    <div
      className={css(s.hero, s[theme])}
      style={{
        background: image ? `url(${image.url})` : 'white',
      }}
    >
      <div className={s.hero__container}>
        <div className={s.content__left} ref={contentRef}>
          <HeadingReveal tag="h1" headingRef={headingRef}>
            {RichText.asText(slice.primary.heading)}
          </HeadingReveal>

          <div className={s.content__copy} ref={copyRef}>
            {RichText.render(slice.primary.copy, linkResolver, htmlSerializer)}
          </div>
          <div className={s.content__button} ref={buttonRef}>
            <ArrowButton href={buttonLink}>{slice.primary.button_label}</ArrowButton>
          </div>
        </div>
  
      </div>
    </div>
  );
};
  

Ответ №1:

Если вы используете встроенный <Link> компонент для создания этой навигации, этого не должно произойти, поскольку @reach/router он не запускается и не перерисовывается при навигации по той же странице. Там нет никакой регидратации.

Если вы используете anchor ( <a> ), вы обновляете всю страницу, поэтому все ваши компоненты будут запущены снова.

Кроме того, еще один обходной путь, который может помочь в вашем случае, — это использовать a useEffect с пустыми deps ( [] ) , создавая componentDidMount эффект. В этом случае, поскольку страница не перезагружается, она не будет запущена снова:

   const [tl] = useState(new TimelineLite({ delay: 0.5 }));

  useEffect(() => {
    tl.to(contentRef.current, { css: { visibility: 'visible' }, duration: 0 })
      .from(headingRef.current, { y: 65, ease: Power2.easeOut, duration: 1 })
      .from(copyRef.current, { opacity: 0, y: 20, ease: Power2.easeOut, duration: 1 }, 0.5)
      .from(buttonRef.current, { opacity: 0, y: 10, ease: Power2.easeOut, duration: 1 }, 1);
    return () => unmountFunction() // unmount to avoid infinite triggers
  }, []);
  

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

Чтобы избежать бесконечных триггеров, вам также может потребоваться размонтировать компонент return () => unmountFunction() .

Комментарии:

1. Спасибо, Ферран, ты дал много ответов! Я использую встроенный <Link> компонент, который меня немного озадачил. Я попробую это завтра и попытаюсь больше разобраться в том, почему <Link> это не работает.

2. Итак, похоже, что проблема заключается только в useEffect том, что он запускается несколько раз. Если я удаляю временную шкалу из компонента, он не перезагружается. Я пытался удалить tl как зависимость для useEffect , но он по-прежнему запускает код при каждом нажатии.

3. Еще раз привет, Ферран! Итак, я все еще сталкиваюсь с той же проблемой, и даже удаление tl из массива зависимостей не работает; он запускается при каждом нажатии. У вас есть какие-либо другие предложения или ресурсы, которые я должен проверить?

4. Я предполагаю размонтировать useEffect , но я не уверен, как справиться с этим с помощью GSAP. github.com/hzdg/gsap-react-plugin/issues/6