useEffect 模拟 componentWillUnmount 不 return 更新状态

useEffect simulating componentWillUnmount does not return updated state

我有一个使用 useState 初始化状态的功能组件,然后通过输入字段更改此状态。

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

这是我正在尝试做的事情的简单表示(这不是我的实际组件):

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;

我将状态初始化为 "initial." 然后我使用输入字段更改状态,比如我输入 "new text." 但是,当组件处于卸载状态时,会记录 "initial"到控制台而不是 "new text."

为什么会这样?如何在卸载时访问当前更新状态?

非常感谢!

编辑:

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

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

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

Cleaning up an effect

The clean-up function runs before the component is removed from the UI to prevent memory leaks. Additionally, if a component renders multiple times (as they typically do), the previous effect is cleaned up before executing the next effect. In our example, this means a new subscription is created on every update. To avoid firing an effect on every update, refer to the next section.

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

Effect hook docs

If you pass an empty array ([]), the props and state inside the effect will always have their initial values. While passing [] as the second argument is closer to the familiar componentDidMount and componentWillUnmount mental model, there are usually better solutions to avoid re-running effects too often.

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

编辑

useRef

useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

...

It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.

使用 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,您会注意到输入中的每次更改都会将之前的状态记录到控制台。

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