当前位置: 首页 > 知识库问答 >
问题:

useEffect模拟组件WillUnmount不会返回更新状态

阮雅达
2023-03-14

我有一个功能组件,它用useState初始化一个状态,然后通过一个输入字段改变这个状态。

然后,我有一个useEffect钩子来模拟componentWillUnmount,以便在组件卸载之前,将当前更新的状态记录到控制台。但是,将记录初始状态,而不是当前状态。

这是我试图做的一个简单的表示(这不是我的实际组件):

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

const Input = () => {
    const [text, setText] = useState('aaa');

    useEffect(() => {
        return () => {
            console.log(text);
        }
    }, [])

    const onChange = (e) => {
        setText(e.target.value);
    };

    return (
        <div>
            <input type="text" value={text} onChange={onChange} />
        </div>
    )
}

export default Input;

我将状态初始化为“初始”然后我使用输入字段来改变状态,比如我键入“新文本”但是,当卸载中的组件时,“初始”将记录到控制台,而不是“新文本”

为什么会发生这种情况?如何在卸载时访问当前更新的状态?

非常感谢!

编辑:

将文本添加到使用效果依赖关系数组并不能解决我的问题,因为在我的现实场景中,我想做的是根据当前状态触发异步操作,并且每次“文本”状态更改时这样做是没有效率的。

我正在寻找一种方法,只有在组件卸载之前才能获得当前状态。

共有1个答案

刘兴朝
2023-03-14

您已经有效地记住了初始状态值,因此当组件卸载该值时,返回的函数在其作用域中包含了该值。

清理效果

清理功能在从UI中删除组件之前运行,以防止内存泄漏。此外,如果组件渲染多次(通常如此),则在执行下一个效果之前会清除上一个效果。在我们的示例中,这意味着每次更新都会创建一个新订阅。要避免在每次更新时触发效果,请参阅下一节。

为了在调用cleanup函数时获得最新状态,您需要在依赖项数组中包含文本,以便更新函数。

效果挂钩文件

如果传递一个空数组([]),效果中的道具和状态将始终具有其初始值。当传递[]时,由于第二个参数更接近于熟悉的组件didmount组件willunmount心智模型,通常有更好的解决方案来避免过于频繁地重新运行效果。

这意味着返回的“清理”函数仍然只访问前一个渲染周期的状态和道具。

编辑

使用参考

useRef返回一个可变ref对象,该对象的。当前属性被初始化为传递的参数(初始值)。返回的对象将在组件的整个生存期内持续存在。

...

它可以方便地保留任何可变值,类似于您在类中使用实例字段的方式。

使用ref将允许您缓存可以在清理函数中访问的当前text引用。

/编辑

组成部分

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

const Input = () => {
  const [text, setText] = useState('aaa');

  // #1 ref to cache current text value
  const textRef = useRef(null);
  // #2 cache current text value
  textRef.current = text;

  useEffect(() => {
    console.log("Mounted", text);

    // #3 access ref to get current text value in cleanup
    return () => console.log("Unmounted", text, "textRef", textRef.current);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    console.log("current text", text);
    return () => {
      console.log("previous text", text);
    }
  }, [text])

  const onChange = (e) => {
    setText(e.target.value);
  };

  return (
    <div>
      <input type="text" value={text} onChange={onChange} />
    </div>
  )
}

export default Input;

使用返回的清理函数中的console.log,您将注意到在输入中的每次更改时,以前的状态都会记录到控制台中。

在这个演示中,我已经在effect中记录了当前状态,在cleanup函数中记录了上一个状态。请注意,“清理”函数首先记录下一个渲染周期的当前日志。

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

  • 让我解释一下这段代码的结果,以便轻松地询问我的问题。 如果我想让这个组件只在卸载时保持日志“清理”,我只需要将的第二个参数更改为。 但是,如果将更改为,不再实现名称输入的。 我想做的是,使组件只支持名称输入和。(仅在卸载组件时,日志记录“已清除”)

  • 我有一个带有两组按钮(功能和目标)的界面。当我点击一个按钮时,我希望它从一个团队转到另一个团队。我正在用react和redux实现这一点。我唯一的问题是,当状态更新并且我成功地记录了更新的状态时,除非我使用forceUpdate(),否则组件不会更新。我不明白的是,既然状态更新成功,组件不应该自动重新渲染吗? 一些js 正如您所看到的,当我单击一个按钮时,我触发updateLists函数,该函数将

  • 问题内容: 我有一个问题要Ajax更新ui:repeat。更新是从ui:repeat外部的commandButton触发的(请参见下面的代码)。需要可变的 priceHour 来计算其他价格(周,Monat ..) 当我单击按钮时,什么也没有发生,并且ui:repeat和价格未更新。怎么了? 我也尝试过 更新“ myForm:alvs” , 更新“:myForm:alvs” :什么都没有! 我正在

  • 更新树结构中的嵌套组件时遇到问题。我创建了以下示例来说明这个问题:Codesandbox.io 为完整起见,这是正在嵌套的组件: 树中的节点在单击时应该是可选择的,我还希望在所有子节点中(递归地)切换所选状态。我想我可以通过将通过道具传递给孩子们来实现这一点,不幸的是,这似乎不起作用。 但是,子对象使用其旧状态重新呈现(可以理解,因为它们没有通过构造函数重新初始化)。正确的处理方法是什么? 我还尝

  • 我的Redux状态是如何更新的,可以在pokelist.js文件中注销,但是我的状态变量没有设置好,cardList还是一个空数组,我如何正确设置状态?我注销pokelist.js文件中的集合,它首先注销一个空数组,然后是一个包含元素的数组。