javascript - 尝试在 useEffect 挂钩中使用清理功能来清理 img.onload
问题描述
我最近构建了一个 React 组件(称为 ItemIndexItem),它在我的应用程序上显示图像。例如,我有一个 Search 组件,它将显示已过滤项目的索引。显示的每个项目都是一个 ItemIndexItem 组件。单击 ItemIndexItem 会将您带到使用相同 ItemIndexItem 的 ItemShow 页面。
搜索.jsx
render() {
return (
<ul>
<li key={item.id}>
<div>
<Link to={`/items/${item.id}`}>
<ItemIndexItem src={item.photos[0].photoUrl} />
<p>${item.price}</p>
</Link>
</div>
</li>
...more li's
</ul>
)
}
ItemIndexItem.jsx
import React, { useState, useEffect } from "react";
export default function ItemIndexItem(props) {
const [imageIsReady, setImageIsReady] = useState(false);
useEffect(() => {
let img = new Image();
img.src = props.src;
img.onload = () => {
setImageIsReady(true);
};
});
if (!imageIsReady) return null;
return (
<div>
<img src={props.src} />
</div>
);
}
除了控制台中抛出的内存泄漏错误外,该组件完全按预期工作:
无法对未安装的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要解决此问题,请在 useEffect 清理函数中取消所有订阅和异步任务。
在 ItemIndexItem(由 ItemShow 创建)
在 div 中(由 ItemShow 创建)
作为参考,这是我渲染 ItemIndexItem 的 ItemShow 中的代码:
ItemShow.jsx
return (
...
<div>
<ul>
{this.props.item.photos.map(photo => {
return (
<li key={photo.photoUrl}>
<div>
<ItemIndexItem type='show' src={photo.photoUrl} />
</div>
</li>
);
})}
</ul>
</div>
...
我尝试使用 useEffect 返回函数设置img
为 null:
return () => img = null;
然而,这无济于事。由于我没有创建订阅,因此没有要删除的订阅。所以我认为问题在于.onload
.
解决方案
您正在设置不再安装的组件的状态。您可以使用useRef
钩子来确定您的组件是否仍然安装,例如:
function useIsMounted() {
const isMounted = React.useRef(true);
React.useEffect(() => {
return () => {
isMounted.current = false;
};
}, []);
return isMounted;
}
在你的ItemIndexItem
...
export default function ItemIndexItem(props) {
const isMounted = useIsMounted();
const [imageIsReady, setImageIsReady] = useState(false);
...
img.onload = () => {
if (isMounted.current) {
setImageIsReady(true);
}
...
}
如useRef的 React 文档中所述。
useRef 返回一个可变 ref 对象,其 .current 属性初始化为传递的参数 (initialValue)。返回的对象将在组件的整个生命周期内持续存在。
这意味着您可以使用它来创建对 HTML 元素的引用,但您也可以在该引用中放置其他变量,例如布尔值。对于我的“useIsMounted”钩子,它在初始化时将其设置为已安装,并在卸载时将其设置为未安装。
推荐阅读
- reactjs - 删除是否安全
来自`_document.js`? - php - 我正在尝试创建搜索字段
- android - 使用正则表达式和 Kotlin 获取字符串中模式的索引
- python - PyQt - 如何在不关闭对话框窗口的情况下停止执行
- css - 移动友好的 Bootstrap 面包屑标签
- arrays - 在不更改输入的情况下在数组中查找重复项?
- c++ - 字节序会导致读取或写入操作冲突吗?
- systemctl - 从 setuid root 程序运行“systemctl restart ___”而不询问 root 密码?
- python - 获取pandas groupby中组的所有值
- php - puPHPeteer 在无头模式下使用时会永远占用