当前位置: 首页 > 面试题库 >

React Hooks useState + useEffect + event给出陈旧状态

穆轶
2023-03-14
问题内容

我正在尝试将事件发射器与React
useEffect和一起使用useState,但是它始终获取初始状态而不是更新状态。如果我直接调用事件处理程序(即使使用),也可以使用setTimeout

如果我将值传递给useEffect()第二个参数,它将使其起作用,但是,每当值更改时(这是击键触发的),这都会导致事件发射器重新订阅。

我究竟做错了什么?我试过useStateuseRefuseReducer,和useCallback,并不能得到任何工作。

这是复制品:

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

import { Controlled as CodeMirror } from "react-codemirror2";

import "codemirror/lib/codemirror.css";

import EventEmitter from "events";



let ee = new EventEmitter();



const initialValue = "initial value";



function App(props) {

  const [value, setValue] = useState(initialValue);



  // Should get the latest value, both after the initial server load, and whenever the Codemirror input changes.

  const handleEvent = (msg, data) => {

    console.info("Value in event handler: ", value);

    // This line is only for demoing the problem. If we wanted to modify the DOM in this event, we would instead call some setState function and rerender in a React-friendly fashion.

    document.getElementById("result").innerHTML = value;

  };



  // Get value from server on component creation (mocked)

  useEffect(() => {

    setTimeout(() => {

      setValue("value from server");

    }, 1000);

  }, []);



  // Subscribe to events on component creation

  useEffect(() => {

    ee.on("some_event", handleEvent);

    return () => {

      ee.off(handleEvent);

    };

  }, []);



  return (

    <React.Fragment>

      <CodeMirror

        value={value}

        options={{ lineNumbers: true }}

        onBeforeChange={(editor, data, newValue) => {

          setValue(newValue);

        }}

      />

      {/* Everything below is only for demoing the problem. In reality the event would come from some other source external to this component. */}

      <button

        onClick={() => {

          ee.emit("some_event");

        }}

      >

        EventEmitter (doesnt work)

      </button>

      <div id="result" />

    </React.Fragment>

  );

}



export default App;

这是具有相同代码的代码沙箱App2

https://codesandbox.io/s/ww2v80ww4l

App组件具有3种不同的实现-EventEmitter,pubsub-js和setTimeout。仅setTimeout有效。

编辑

为了阐明我的目标,我只是希望其中handleEvent的值在所有情况下都与Codemirror值匹配。单击任何按钮时,应显示当前的代码镜像值。而是显示初始值。


问题答案:

value在事件处理程序中是过时的,因为它从定义它的闭包中获取其值。除非每次value更改都重新订阅新的事件处理程序,否则它将不会获得新值。

解决方案1:对发布效果进行第二个论证[value]。这使事件处理程序获得正确的值,但也使效果在每次击键时再次运行。

解决方案2:使用ref将最新的存储value在组件实例变量中。然后,产生一个效果,每当value状态更改时,该效果仅更新此变量。在事件处理程序中,请使用ref,而不是value

const [value, setValue] = useState(initialValue);
const refValue = useRef(value);
useEffect(() => {
    refValue.current = value;
});
const handleEvent = (msg, data) => {
    console.info("Value in event handler: ", refValue.current);
};

https://reactjs.org/docs/hooks-faq.html#what-c​​an-i-do-if-my-effect-
dependencies-change-too-oftenten

该页面上似乎还有其他一些解决方案也可能起作用。非常感谢@Dinesh的帮助。



 类似资料:
  • 在Autoconf的第2版,大部分宏被重新命名以使用更加统一和具有描述性的命名方案。下面是被重新命名了的宏的原来名字, 随后给出了这些宏现在的名字。虽然为了保持向后兼容,旧名字仍然能够被autoconf程序所接受,旧名字都 被看作过时的。关于新的命名方案,参见 宏名 。AC—ALLOCAAC—FUNC—ALLOCA AC—ARG—ARRAY 因为用途有限而被删除了。AC—CHAR—UNSIGNED

  • 下面的示例是一个计时器组件,它有一个按钮(用于启动计时器)和两个标记,显示经过的秒数和经过的秒数乘以2。 但是,它不工作(CodeSandbox演示) 守则 问题 在使用效果调用中,秒值将始终等于上次呈现使用效果块时(当isActive上次更改时)的值。这将导致setDouble秒(秒*2)语句失败。React Hooks ESLint插件给我一个关于这个问题的警告: React Hook use

  • 我正在写一个小的抓取程序,它导航到一个包含链接列表的页面, 它单击第一个链接,打开一个新页面,获取一些详细信息,然后导航回包含链接列表的页面,然后尝试查找下一个链接,但我得到: 组织。openqa。硒。StaleElementReferenceException:stale元素引用:元素未附加到页面文档 你知道我该怎么避免吗?

  • 问题内容: 环境 hibernate4.2 ojdbc6-Oracle 11.2.0.3.0 JDBC 4.0 Oracle数据库11g 问题 我们遵循了许多建议,以如下方式配置Hibernate批处理: 我们检查了日志,发现生成的SQL语句已批处理。但是,如果两个事务同时修改相同版本的实体行,则Hibernate将成功提交它们,导致最后提交的事务中的冲突更新丢失(两个事务中都保存了无冲突的数据,

  • 我有以下Useffect钩子: 然而,我得到以下警告: React Hook useEffect缺少依赖项:“image.height”、“image.img”、“image.width”、“scaleProperties.scaleInstance”和“scaleProperties.scaleValueMm”。请包含它们或删除依赖项数组 Image和scaleProperties也是组件的状态

  • 我不熟悉React钩子和React 16.13.1。 我将实现能够处理登录的Auth组件。 但是它似乎没有正确更新状态,即使使用响应对象调用。 这个代码有什么问题?