【问题标题】:Cannot get rid of Warning: React state update on unmounted component during tests RTL无法摆脱警告:在测试 RTL 期间对未安装的组件做出反应状态更新
【发布时间】:2021-06-02 19:09:03
【问题描述】:

我正在编写集成测试。此文件呈现<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 已经运行并且执行了一个副作用,即重定向到结果页面。

我知道我误解了一些东西,只是不知道是什么。感谢任何帮助!

【问题讨论】:

    标签: reactjs jestjs react-hooks react-testing-library


    【解决方案1】:

    考虑使用'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;
    

    【讨论】:

    • 谢谢,阿尼。这是一个很好的答案,我已经实现了类似的东西来使警告消失。我想我也在试图弄清楚如何在不污染应用程序代码的情况下做到这一点(仅在测试中执行检查或中止)。)
    • 很高兴为您提供帮助!我通常在我的应用程序的每个组件中执行我需要在 UseEffect() 钩子内设置状态的检查。这可能看起来太多了,但到目前为止,我还没有找到摆脱上述警告的另一种方法。
    • 我把它做成了一个自定义钩子,所以我只需在组件的最顶部调用const isMounted = useIsMounted(),然后用if (!isMounted.current) return;检查我想提前返回的时间这样我就不会添加给组件带来了很多不必要的混乱。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-20
    • 1970-01-01
    • 2021-02-24
    • 2018-10-06
    • 2020-11-17
    • 2021-11-09
    相关资源
    最近更新 更多