【问题标题】:React hooks value is not accessible in event listener function在事件侦听器函数中无法访问 React hooks 值
【发布时间】:2019-03-24 17:16:56
【问题描述】:

我决定为我的组件使用 React 钩子,使用窗口宽度和调整大小事件侦听器。问题是我无法访问我需要的当前值。我得到了在添加事件监听器时设置的嵌套值。

将函数传递给值设置器函数对我来说不是一个解决方案,因为它会强制渲染并破坏我的其他功能。

我附上简单的例子来呈现核心问题:

import React, { Component, useState, useEffect } from 'react';
import { render } from 'react-dom';

const App = () => {
  const [width, setWidth] = useState(0);

  const resize = () => {
    console.log("width:", width); // it's always 0 even after many updates
    setWidth(window.innerWidth);
  };

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

  return <div>{width}</div>;
}

render(<App />, document.getElementById('root'));

LIVE DEMO IS HERE

请帮忙。

【问题讨论】:

    标签: javascript reactjs addeventlistener react-hooks


    【解决方案1】:

    每次渲染都会获得resize 函数的新副本。每个副本捕获width 的当前值。您的听众有一个副本,该副本是在第一次渲染时使用width = 0 创建的。

    要解决此问题,您有多种选择:

    1. width 更改时更新侦听器

      useEffect(() => {
        resize();
        window.addEventListener("resize", resize);
        return () => window.removeEventListener("resize", resize);
      }, [width]);
      
    2. 使用functional updates获取监听器的当前宽度

      const resize = () => {
        setWidth(oldWidth => {
          console.log("width:", oldWidth);
          return window.innerWidth
        });
      };
      
    3. 将宽度存储在mutable reference

      const widthRef = useRef(width);
      
      const resize = () => {
        console.log("width:", widthRef.current);
        widthRef.current = window.innerWidth;
        setWidth(window.innerWidth);
      };
      

    【讨论】:

    • 是的。第二个useEffect 无助于解决这个问题。您要么需要在width 更改时删除-添加侦听器,要么以其他方式获取width 的当前值。因此有 3 种可能的解决方案。第一个是最简单的。
    • 您的代码优化不佳,对原始问题没有真正帮助。它只是隐藏了问题。首先useEffect 设置一个事件监听器,它将width 重置为初始值。这会触发重新渲染和第二个useEffect。第二个useEffectwidth 设置为正确的值。因此,每个调整大小事件都会触发两次重新渲染,而不是一次,并且其中一个 resize 调用使用了错误的值。
    • 我喜欢第三种方式。谢谢。
    【解决方案2】:

    另一种获取数据的方法是从组件中设置变量

    DEMO

    import React, { Component, useState, useEffect } from 'react';
    import { render } from 'react-dom';
    
    //******* 
    const appData = {
          width:0
    }
    //*******
    
    const App = () => {
      const [width, setWidth] = useState(0);
    
      const resize = () => {
        //******* get width
        console.log('===>',appData.width);
        //*******
    
        console.log("width:", width); // it's always 0 even after many updates
        setWidth(window.innerWidth);
        //******* update width
        appData.width = window.innerWidth;
        //*******
      };
    
      useEffect(() => {
        resize();
        window.addEventListener("resize", resize);
        return () => window.removeEventListener("resize", resize);
      }, []);
    
      return <div>{width}</div>;
    }
    
    render(<App />, document.getElementById('root'));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-17
      • 2020-02-25
      • 1970-01-01
      • 2021-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多