setInterval не входит в состав React Functional Component - PullRequest
0 голосов
/ 25 марта 2020

Я создал компонент React, который может при необходимости прокручивать содержимое до верхней части страницы. Если вы посмотрите на пример песочницы кода, кнопка «GO Top» отобразится, если прокрутить немного вниз, если вы щелкните по ней, страница будет прокручиваться вверх, и если вы попытаетесь прокрутить вниз назад, это всегда приведет вас к началу страницы. Причина в том, что таймер не очищен, так как intervalId всегда равен нулю. в частности, если вы проверяете строку №20, intervalId всегда равен нулю, я думаю, это может быть связано с закрытием, но я не могу это исправить пожалуйста, помогите.

Спасибо!

код размещен ниже, код codeanbox здесь

import React from "react";

const GoTop = ({ scrollStepInPx, delayInMs }) => {
  const [intervalId, setIntervalId] = React.useState(null);
  const [position, setPosition] = React.useState(false);

  React.useEffect(() => {
    document.addEventListener("scroll", () => {
      if (window.scrollY > 200) {
        setPosition(true);
      } else {
        setPosition(false);
      }
    });
    window.scrollTo(0, 0);
  }, []);

  const onScrollStep = () => {
    if (window.pageYOffset === 0) {
      console.log(intervalId); //always null
      clearInterval(intervalId);
      return;
    }
    window.scroll(0, window.pageYOffset - scrollStepInPx);
  };

  const scrollToTop = () => {
    const id = setInterval(onScrollStep, delayInMs);
    setIntervalId(() => id);
  };

  const renderGoTopIcon = () => {
    if (position) {
      return (
        <button className="go-top" onClick={scrollToTop} type="button">
          Go Top
        </button>
      );
    }
    return null;
  };

  return <>{renderGoTopIcon()}</>;
};

export default GoTop;

1 Ответ

0 голосов
/ 25 марта 2020

Я сделал так, как это, эти посты помогли. https://dmitripavlutin.com/react-hooks-stale-closures/

import React from "react";

const GoTop = ({ scrollStepInPx, delayInMs }) => {
  const [position, setPosition] = React.useState(false);

  React.useEffect(() => {
    document.addEventListener("scroll", () => {
      if (window.scrollY > 200) {
        setPosition(true);
      } else {
        setPosition(false);
      }
    });
    window.scrollTo(0, 0);
  }, []);

  const scrollToTop = () => {
    let intervalId;
    //move the event handle here, NOT use hooked state variable intervalId
    const onScrollStep = () => {
      if (window.pageYOffset === 0) {
        clearInterval(intervalId);
        return;
      }
      window.scroll(0, window.pageYOffset - scrollStepInPx);
    };

    intervalId = setInterval(onScrollStep, delayInMs);
  };

  const renderGoTopIcon = () => {
    if (position) {
      return (
        <button className="go-top" onClick={scrollToTop} type="button">
          Go Top
        </button>
      );
    }
    return null;
  };

  return <>{renderGoTopIcon()}</>;
};

export default GoTop;
...