我正在try 了解react的useEffect清理.

我遇到了这个关于如何使用清理的示例.

const [data, setData] = useState({})

useEffect(() => {
    // set our variable to true
    let isApiSubscribed = true;
    axios.get(API).then((res) => {
        if (isApiSubscribed) {
            // handle success
            setData(res.data)
        }
    });
    return () => {
        // cancel the subscription
        isApiSubscribed = false;
    };
}, []);

但我想问,是否有可能在组件卸载和调用清理之间解决promise ,从而导致错误,即访问已解除分配的状态?

推荐答案

虽然我无法准确地告诉您何时调用useEffect的unsubscribe函数比"卸载组件时"更具体,但我can回答了您关于何时调用它的含义的问题:

是否有可能在组件卸载和调用清理之间解决promise ,从而导致错误,即访问已解除分配的状态?

在编写的代码中,promise 可以解决after个组件的卸载问题.您的isApiSubscribed标志是一种隐藏在开发模式中发生这种情况时可能显示的警告的方法,但它是not the correct way of dealing with this scenario.

当react在开发模式下运行时发生这种情况,您可能会收到如下警告消息:

警告:无法对已卸载的组件执行react 状态更新.这是一个no-op,但它表示应用程序中存在内存泄漏.要修复此问题,请取消componentWillUnmount方法中的所有订阅和异步任务.

此警告消息的要点是,在卸载特定组件后,应小心停止执行不再相关的工作.不调用setData会阻止您更新状态,但HTTP请求的工作仍将始终完成,即使组件已卸载.That'sreact 是告诉你应该考虑取消.

改变此模式以避免花费不必要资源的"正确"方法是在组件卸载时停止HTTP请求的执行,这将导致promise 拒绝:

useEffect(() => {
    const abortController = new AbortController();    
    axios.get(API, { signal: abortController.signal }).then((res) => {
        setData(res.data)
    });
    return () => {
        abortController.abort();
    };
}, []);

这不仅确保了您不会对已卸载的组件调用setData(这是一项相对琐碎的工作),而且还确保了在卸载组件时取消更大的工作,即HTTP请求(以及相关的响应处理).

从理论上讲,可能会发生以下一系列事件:

  1. 任务开始
  2. 任务完成
  3. promise 解决
  4. 组件卸载
  5. 触发下一个事件tick,并调用传递给then()的continuation,调用setData(),触发警告消息

但这需要精确的时间,警告信息的精神是防止更常见的情况:

  1. 任务开始
  2. 组件卸载
  3. 任务完成
  4. promise 解决
  5. 下一个事件勾号触发器

Javascript相关问答推荐

如何为GrapesJS模板编辑器创建自定义撤销/重复按钮?

基于变量切换隐藏文本

在Angular中将样式应用于innerHTML

如何使用JavaScript将文本插入空div

单击ImageListItemBar的IconButton后,在Material—UI对话框中显示图像

引用在HTMLAttributes<;HTMLDivElement>;中不可用

Reaction Native中的范围滑块

这个值总是返回未定义的-Reaction

如何修复我的数据表,以使stateSave正常工作?

JavaScript不重定向配置的PATH

OpenAI转录API错误请求

FireBase云函数-函数外部的ENV变量

处理TypeScrip Vue组件未初始化的react 对象

我为什么要使用回调而不是等待?

Refine.dev从不同的表取多条记录

将字符串解释为数字;将其重新编码为另一个基数

如何格式化API的响应

在Reaction Native中,ScrolltoIndex在结束时不一致地返回到索引0

如何在单击Search按钮时更新Reaction组件?

在不使用AJAX的情况下将JavaScript数组值传递给Laravel控制器?