【问题标题】:Mouse position in state/props vs multiple event listeners状态/道具中的鼠标位置与多个事件侦听器
【发布时间】:2023-02-26 04:47:53
【问题描述】:

我正在寻找一些指导。

我有一个 React 应用程序,其中有多个组件 (10-20) 需要在鼠标位置发生变化时执行操作。

目前我在父组件中有一个鼠标移动事件侦听器,它将鼠标位置存储在状态变量中并将其传递给道具中的子组件。在子组件中,useEffect 在更改时会触发一些操作。然而,这似乎不是最佳方法,因为 ESLint 会触发eslint react-hooks/exhaustive-deps 警告,这意味着 useEffect 可能不适用于这种用法。

简化设置:

const ParentComponent = () => {
  const [position, setPosition] = useState({x: 0, y: 0});

  useEffect(() => {
    const throttleMouseMove = throttle((event: any) => {
      setPosition({x: event.clientX, y: event.clientY});
    }, 50);

    window.addEventListener("mousemove", throttleMouseMove); 
    return () => {
      window.removeEventListener("mousemove", throttleMouseMove);
    };  
  }, []);

  return (
    <ChildComponent mousePosition={position} />
  )
};

.

const ChildComponent = (props) => {
  useEffect(() => {
    // Do something
  }, [props.mousePosition]);
}

我考虑过将鼠标移动事件侦听器添加到需要对此进行操作的所有组件。但是多个事件监听器会影响性能吗?特别是鼠标移动侦听器,因为它经常触发 - 即使我限制了它。

有第三种选择吗?

希望有人可以提供一些指导。

【问题讨论】:

    标签: reactjs react-hooks event-listener


    【解决方案1】:

    避免 ESLint 警告并提高性能的一种潜在解决方案是使用上下文来存储鼠标位置,并让需要对其进行操作的子组件订阅该上下文。这样,您就可以避免将鼠标位置作为道具向下传递,这可能会触发子组件中不必要的重新渲染。

    这是一个示例实现:

    // MousePositionContext.js
    import React, { createContext, useState, useEffect } from "react";
    
    export const MousePositionContext = createContext({ x: 0, y: 0 });
    
    export const MousePositionProvider = ({ children }) => {
    const [position, setPosition] = useState({ x: 0, y: 0 });
    
    useEffect(() => {
    const throttleMouseMove = throttle((event) => {
    setPosition({ x: event.clientX, y: event.clientY });
    }, 50);
    window.addEventListener("mousemove", throttleMouseMove);
    return () => {
      window.removeEventListener("mousemove", throttleMouseMove);
    };
    }, []);
    
    return (
    <MousePositionContext.Provider value={position}>
    {children}
    </MousePositionContext.Provider>
    );
    };
    
    // ParentComponent.js
    import React from "react";
    import { MousePositionProvider } from "./MousePositionContext";
    import ChildComponent1 from "./ChildComponent1";
    import ChildComponent2 from "./ChildComponent2";
    // ...
    
    const ParentComponent = () => {
    return (
    <MousePositionProvider>
    <ChildComponent1 />
    <ChildComponent2 />
    {/* ... */}
    </MousePositionProvider>
    );
    };
    
    // ChildComponent1.js
    import React, { useContext, useEffect } from "react";
    import { MousePositionContext } from "./MousePositionContext";
    
    const ChildComponent1 = () => {
    const { x, y } = useContext(MousePositionContext);
    
    useEffect(() => {
    // Do something with mouse position
    }, [x, y]);
    
    return (
    // ...
    );
    };
    
    // ChildComponent2.js
    import React, { useContext, useEffect } from "react";
    import { MousePositionContext } from "./MousePositionContext";
    
    const ChildComponent2 = () => {
    const { x, y } = useContext(MousePositionContext);
    
    useEffect(() => {
    // Do something else with mouse position
    }, [x, y]);
    
    return (
    // ...
    );
    };
    

    通过使用上下文方法,您将只有一个鼠标移动事件的事件侦听器,它会更新上下文中的鼠标位置。需要对鼠标位置进行操作的子组件将订阅上下文,并且仅在鼠标位置发生变化时才重新渲染。

    我希望这有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-01
      • 2017-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-02
      • 1970-01-01
      相关资源
      最近更新 更多