useEffect 模拟 componentWillUnmount 不返回更新状态 [英] useEffect simulating componentWillUnmount does not return updated state

查看:58
本文介绍了useEffect 模拟 componentWillUnmount 不返回更新状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

import React, { useEffect, useState } from 'react';const 输入 = () =>{const [text, setText] = useState('aaa');useEffect(() => {返回 () =>{控制台日志(文本);}}, [])const onChange = (e) =>{setText(e.target.value);};返回 (<div><input type="text" value={text} onChange={onChange}/>

)}导出默认输入;

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

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

非常感谢!

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

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

解决方案

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

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

I have a functional component that initializes a state with useState, then this state is changed via an input field.

I then have a useEffect hook simulating componentWillUnmount so that, before the component unmounts, the current, updated state is logged to the console. However, the initial state is logged instead of the current one.

Here is a simple representation of what I am trying to do (this is not my actual component):

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;

I initialize the state as "initial." Then I use the input field to change the state, say I type in "new text." However, when the component in unmounted, "initial" is logged to the console instead of "new text."

Why does this happen? How can I access the current updated state on unmount?

Many thanks!

Edit:

Adding text to useEffect dependency array doesn’t solve my problem because in my real-world scenario, what I want to do is to fire an asynchronous action based on the current state, and it wouldn’t be efficient to do so everytime the "text" state changes.

I’m looking for a way to get the current state only right before the component unmounts.

解决方案

You've effectively memoized the initial state value, so when the component unmounts that value is what the returned function has enclosed in its scope.

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.

In order to get the latest state when the cleanup function is called then you need to include text in the dependency array so the function is updated.

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.

This means the returned "cleanup" function still only accesses the previous render cycle's state and props.

EDIT

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.

Using a ref will allow you to cache the current text reference that can be accessed within the cleanup function.

/EDIT

Component

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;

With the console.log in the returned cleanup function you'll notice upon each change in the input the previous state is logged to console.

In this demo I've logged current state in the effect and previous state in the cleanup function. Note that the cleanup function logs first before the current log of the next render cycle.

这篇关于useEffect 模拟 componentWillUnmount 不返回更新状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆