useEffect 模拟 componentWillUnmount 不返回更新后的状态

问题描述 投票:0回答:1

我有一个功能组件,它使用 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;

我将状态初始化为“初始”。然后我使用输入字段来更改状态,假设我输入“新文本”。但是,当组件卸载时,控制台会记录“初始”而不是“新文本”。

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

非常感谢!

编辑:

向 useEffect 依赖项数组添加文本并不能解决我的问题,因为在我的现实场景中,我想要做的是根据当前状态触发异步操作,并且每次都这样做效率不高。 “文本”状态发生变化。

我正在寻找一种方法,仅在组件卸载之前获取当前状态。

reactjs react-hooks use-effect
1个回答
5
投票

您已经有效地记住了初始状态值,因此当组件卸载时,那个值就是返回的函数包含在其范围内的值。

清理效果

清理功能在组件从 UI 中删除之前运行 以防止内存泄漏。此外,如果一个组件呈现多个 次(正如他们通常所做的那样),先前的效果会在之前被清除 执行下一个效果。在我们的例子中,这意味着一个新的 每次更新时都会创建订阅。为了避免触发效果 每次更新,请参阅下一节。

为了在调用清理函数时获得最新状态,您需要在依赖项数组中包含

text
,以便更新函数。

效果挂钩文档

如果传递一个空数组 (

[]
),则效果内的 props 和状态 总是有它们的初始值。同时将
[]
作为第二个 论点更接近熟悉的
componentDidMount
并且
componentWillUnmount
心理模型,通常有更好的解决方案 以避免过于频繁地重新运行效果。

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

编辑

使用参考

useRef
返回一个可变的 ref 对象,其
.current
属性为 初始化为传递的参数 (
initialValue
)。返回的对象 将在组件的整个生命周期中持续存在。

...

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

使用 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
  useEffect(() => {
    textRef.current = text;
  }, [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,您会注意到输入中的每次更改都会将之前的状态记录到控制台。

Edit zen-leftpad-twogm

在此演示中,我在效果中记录了当前状态,并在清理函数中记录了之前的状态。请注意,清理函数首先在下一个渲染周期的当前日志之前记录。

© www.soinside.com 2019 - 2024. All rights reserved.