javascript - 从滚动事件监听器 react setState 钩子(Hook)

标签 javascript reactjs addeventlistener react-hooks

首先,对于类组件,这可以正常工作并且不会导致任何问题。

但是,在带有钩子(Hook)的功能组件中,每当我尝试从滚动事件监听器的函数 handleScroll 设置状态时,即使我使用 debounce,我的状态也无法更新或应用程序的性能受到严重影响.

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;

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

我做错了什么?如何在不对性能产生巨大影响的情况下从 handleScroll 设置状态?

我创建了一个沙箱来解决这个问题。

Edit React setState from event listener

最佳答案

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

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/

相关文章:

Javascript addEventListener 麻烦

javascript - 如何从数组中过滤掉非日语字符?

java - 是否可以在包含多种监听器类型的 Java 中创建我自己的事件监听器列表?

javascript - 使用 .classList 向已经具有该类的元素添加类是否有任何危害

javascript - redux-saga 第一次不工作

javascript - jQuery - 关闭方法

javascript - 使用垂直鼠标滚轮在 React 组件上水平滚动

javascript - 在react js中使用map重复带有键和值的数组对象

javascript - 按模式对数组进行排序——javascript

javascript - 在 Android Webview 中仅禁用水平滚动