无法摆脱警告:在测试RTL期间对未安装的组件进行React状态更新



我正在编写集成测试。该文件呈现<App />,填充输入,并在每次测试前提交搜索。测试都通过了。然而,我无法摆脱:

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application.

我在应用程序中没有收到此警告,只有测试。我读了几十篇文章,但没有一个解决方案(act()wait()waitFor()等(有任何不同。

这是测试代码,我只留下了导致警告的最小原因(单击submitBtn:后,我获取goBackBtnText

describe('Results Page', () => {
let goBackBtn, nearbyBtn;
beforeEach(async () => {
ZIP_API_MOCK();
FDIC_API_MOCK();
render(<App />);
const zipInput = await screen.findByPlaceholderText(searchFormText.placeholder);
const submitBtn = screen.getByText(searchFormText.submitBtn).closest('button');
input(zipInput, VALID_ZIP_WITH_RESULTS);
userEvent.click(submitBtn);
const goBackBtnText = await screen.findByText((content) =>
content.includes(resultsText.goBackBtn)
);
goBackBtn = goBackBtnText.closest('button');
});
afterEach(() => {
userEvent.click(goBackBtn);
});
it('true', () => {
expect(true).toBeTruthy();
});

发出警告的行:

44 |     }
45 |     if (newResults.fiList.length > 0) fwdToPath = PATHS.RESULTS;
> 46 |     setResults(newResults);
|     ^
47 |     setLoading(false);
48 |   };

这才是真正让我困惑的地方。因为goBackBtn在结果页面上,测试成功地看到了它。所以setResults已经运行,并且执行了一个副作用,即重定向到结果页面。

我知道我误解了什么,只是不确定是什么。感谢您的帮助!

考虑使用'mounted'变量来判断是否应该跳过对setState的调用(清理函数(。

查看下面的例子,获取来自互联网的杂货清单:

import "./App.css";
import React, { useEffect, useState, useRef } from "react";
import { getList, setItem } from "././services/list";

function App() {
const [alert, setAlert] = useState(false);
const [list, setList] = useState([]);
const [itemInput, setItemInput] = useState("");
const mounted = useRef(true);

useEffect(() => {
mounted.current = true;
if (list.length && !alert) {
return;
}
getList().then((items) => {
if (mounted.current) {
setList(items);
}
});
return () => (mounted.current = false);
}, [alert, list]);

const handleSubmit = (e) => {
e.preventDefault();
setItem(itemInput)
//When the setItem promise resolves, clear the input and set the alert message
.then(() => {
if (mounted.current) {
setItemInput("");
setAlert(true);
}
});
};

useEffect(() => {
if (alert) {
setTimeout(() => {
if (mounted.current) {
setAlert(false);
}
}, 1000);
}
}, [alert]);

return (
<div>
<h1>My List</h1>
<ul>
{list.map((item) => (
<li key={item.item}>{item.item}</li>
))}
</ul>
{alert && <h2> Submit Successful</h2>}
<form onSubmit={handleSubmit}>
<label>
<p>New Item</p>
<input
type="text" 
onChange={(event) => setItemInput(event.target.value)}
value={itemInput}
/>
</label>
<button type="submit">Submit</button>
</form>
</div>
);
}

export default App;

最新更新