useEffect模拟componentWillUnmount不返回更新状态

时间:2020-03-18 06:34:36

标签: reactjs

我有一个功能组件,它使用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依赖项数组中添加文本并不能解决我的问题,因为在我的实际场景中,我想做的是基于当前状态触发异步操作,这样做并不高效每当“文本”状态更改时。

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

2 个答案:

答案 0 :(得分:0)

您应将text传递给useEffect

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

答案 1 :(得分:0)

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

Cleaning up an effect

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

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

Effect hook docs

如果传递一个空数组([]),则效果内的 props和状态 将始终具有其初始值。通过[]作为第二个 参数离熟悉的componentDidMount更近,并且 componentWillUnmount心理模型,通常有更好的解决方案 为了避免过于频繁地重新运行效果。

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

编辑

useRef

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

...

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

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

/ EDIT

组件

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时,您会在每次输入更改时注意到以前的状态已记录到控制台。

Edit zen-leftpad-twogm

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

相关问题