首先,使用类组件,可以很好地工作并且不会引起任何问题。

但是,在带有钩子(Hook)的功能组件中,即使我尝试使用滚动事件侦听器的函数handleScroll设置状态,我的状态也无法更新,或者即使我使用了反跳功能,应用程序的性能也受到严重影响。

import React, { useState, useEffect } from "react";
import debounce from "debounce";

let prevScrollY = 0;

const App = () => {
  const [goingUp, setGoingUp] = useState(false);

  const handleScroll = () => {
    const currentScrollY = window.scrollY;
    if (prevScrollY < currentScrollY && goingUp) {
      debounce(() => {
        setGoingUp(false);
      }, 1000);
    }
    if (prevScrollY > currentScrollY && !goingUp) {
      debounce(() => {
        setGoingUp(true);
      }, 1000);
    }

    prevScrollY = currentScrollY;
    console.log(goingUp, currentScrollY);
  };

  useEffect(() => {
    window.addEventListener("scroll", handleScroll);
    return () => window.removeEventListener("scroll", handleScroll);
  }, []);

  return (
    <div>
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
    </div>
  );
};

export default App;

尝试在useCallback函数中使用handleScroll钩子(Hook),但并没有太大帮助。

我究竟做错了什么?如何在不影响性能的情况下从handleScroll设置状态?

我已经为此问题创建了一个沙箱。

javascript - 从滚动事件监听器 react setState Hook-LMLPHP

最佳答案

在您的代码中,我看到了几个问题:

1)useEffect中的[]表示它将看不到任何状态变化,例如goingUp的变化。它将始终看到goingUp的初始值

2)debounce不起作用。它返回一个新的去抖动功能。

3)通常,全局变量是一种反模式,认为它仅在您情况下有效。

4)您的滚动监听器不是被动的,如@skyboyer所述。

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

const App = () => {
  const prevScrollY = useRef(0);

  const [goingUp, setGoingUp] = useState(false);

  useEffect(() => {
    const handleScroll = () => {
      const currentScrollY = window.scrollY;
      if (prevScrollY.current < currentScrollY && goingUp) {
        setGoingUp(false);
      }
      if (prevScrollY.current > currentScrollY && !goingUp) {
        setGoingUp(true);
      }

      prevScrollY.current = currentScrollY;
      console.log(goingUp, currentScrollY);
    };

    window.addEventListener("scroll", handleScroll, { passive: true });

    return () => window.removeEventListener("scroll", handleScroll);
  }, [goingUp]);

  return (
    <div>
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
      <div style={{ background: "orange", height: 100, margin: 10 }} />
    </div>
  );
};

export default App;


https://codesandbox.io/s/react-setstate-from-event-listener-q7to8

关于javascript - 从滚动事件监听器 react setState Hook ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57088861/

10-16 22:39