简体   繁体   English

使用 React 测试库测试时仍然收到“未安装组件的 React 状态更新”错误

[英]Still getting "React state update on an unmounted component" error with React Testing Library tests

I was getting a plethora of errors with my testing code so have taken several steps to improve things.我的测试代码出现大量错误,因此采取了几个步骤来改进。 This article helped: https://binarapps.com/blog/clean-up-request-in-useeffect-react-hook/woodb这篇文章有帮助: https : //binarapps.com/blog/clean-up-request-in-useeffect-react-hook/woodb

I improved the useEffect that I suspected was the problem by introducing AbortController:我提高了useEffect ,我怀疑是通过引入AbortController问题:

useEffect(() => {
  if (companyId && companyId !== -1) {
    const abortController = new AbortController();

    requests.get(`${requests.API_ROOT()}account_management/roles?company_id=${companyId}`)
      .then(response => {
        dispatch({type: UPDATE_ROLES, payload: response.data.roles});
      })
      .catch(error => {
        if (error.response) {
          throw('Error fetching roles: ', error.response.status);
        }
      });

    return () => {
      abortController.abort();
    };
  }
}, [companyId, dispatch]);

I also refactored my test code like this:我还像这样重构了我的测试代码:

it('Should hide modal if Close is pressed', async () => {
  await act(async () => {
    let { getByTestId, getByText, queryByTestId, queryByText } = await renderDom(<AddUsersLauncher />);
    fireEvent.click(queryByText(/^Add Users/i));

    fireEvent.click(getByText(/^Close/i));
    expect(queryByTestId('add-users-modal')).toBeNull();
  });
});

Note: The renderDom function remains the same as before:注意: renderDom函数和以前一样:

const _initialState = {
  session: {
    user: {},
    isLoading: false,
    error: false,
  },
};

function renderDom(component, initialState = _initialState) {
  const store = configureStore(initialState);

  return {
    ...render(
      <Provider store={store}>
        <SessionProvider>
          <ThemeProvider theme={theme}>
            <SystemMessages />
            <CustomComponent />
            {component}
          </ThemeProvider>
        </SessionProvider>
      </Provider>),
    store
  };
}

As per the question from oemera, this is the async call:根据 oemera 的问题,这是异步调用:

export const get = async function(url: string, _options: any) {
  const options = _options || await _default_options();
  return axios.get(url, options);
};

After this refactoring, the errors/warnings have reduced but there's still one appearing:经过这次重构,错误/警告减少了,但仍然出现:

>   Add Users component tests
>     ✓ Should display the Add Users modal (119ms)
>     ✓ Should cancel w/o confirmation modal if no data is entered (34ms)
>     ✓ Should hide modal if Close is pressed (32ms)
>     ✓ Should hide modal if Close is pressed (29ms)
> 
>   console.error
> node_modules/react-dom/cjs/react-dom.development.js:558
>     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. To fix, cancel all subscriptions and asynchronous tasks
> in a useEffect cleanup function.
>         in UsersProvider (at AddUsersModal.js:10)
>         in div (at AddUsersModal.js:9)
>         in AddUsersModal (at AddUsersLauncher.js:16)
> 
> Test Suites: 1 passed, 1 total Tests:       4 passed, 4 total
> Snapshots:   0 total Time:        4.999s Ran all test suites matching
> /AddUsers.test/i.

I've checked all of the code AddUsers... files mentioned but there are no useEffect instances there.我已经检查了所有提到的代码AddUsers...文件,但那里没有useEffect实例。

Any advice on what I should do to remove this warning?关于我应该怎么做才能删除此警告的任何建议?

When you are using axios instead of fetch the abort controller won't work.当您使用axios而不是fetch ,中止控制器将不起作用。 This is how you do it in axios:这是你在 axios 中的做法:

import React, { Component } from 'react';
import axios from 'axios';

class Example extends Component {

  signal = axios.CancelToken.source();

  state = {
    isLoading: false,
    user: {},
  }

  componentDidMount() {
    this.onLoadUser();
  }

  componentWillUnmount() {
    this.signal.cancel('Api is being canceled');
  }

  onLoadUser = async () => {

    try {
      this.setState({ isLoading: true });
      const response = await axios.get('https://randomuser.me/api/', {
        cancelToken: this.signal.token,
      })

      this.setState({ user: response.data, isLoading: true });

    } catch (err) {

      if (axios.isCancel(err)) {

        console.log('Error: ', err.message); // => prints: Api is being canceled
      }
      else {
        this.setState({ isLoading: false });
      }
    }
   } 
   
    render() {

      return (
        <div>
          <pre>{JSON.stringify(this.state.user, null, 2)}</pre>
        </div>
      )
    }
}

source: https://gist.github.com/adeelibr/d8f3f8859e2929f3f1adb80992f1dc09来源: https : //gist.github.com/adeelibr/d8f3f8859e2929f3f1adb80992f1dc09

Note how you pass in a cancelToken instead of the whole signal.请注意您如何传入cancelToken而不是整个信号。 Also you get the signal with axios.CancelToken.source() and you call signal.cancel instead or abortController.abort你也获得与信号axios.CancelToken.source()和调用signal.cancel代替或abortController.abort

So for your example, this should work like this or at least lead you in the right direction:因此,对于您的示例,这应该像这样工作,或者至少将您引向正确的方向:

useEffect(() => {
 if (companyId && companyId !== -1) { 
   const signal = axios.CancelToken.source();
   requests.get(`${requests.API_ROOT()}account_management/roles?company_id=${companyId}`,
   { cancelToken: signal.token})
  .then(response => { 
   dispatch({type: UPDATE_ROLES, 
   payload: response.data.roles}); })
   .catch(error => { 
      if (error.response) { 
         throw('Error fetching roles: '     error.response.status);
    } 
   }); 
   return () => { signal.cancel('Cancelling request...');};
} }, [companyId, dispatch]);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 React 测试库:测试中的更新未包含在 act(...) 中,并且无法对未安装的组件执行 React state 更新 - React testing library: An update inside a test was not wrapped in act(…) & Can't perform a React state update on an unmounted component 反应卸载组件 State 更新错误 - React Unmounted Component State Update Error 在 useEffect 中添加了 isCancelled 标志,但仍然出现“无法在未安装的组件上执行 React state 更新……” - Added isCancelled flag in useEffect, but still getting “Can't perform a React state update on an unmounted component…” React Can't perform a React state update on an unmounted component error - React Can't perform a React state update on an unmounted component error 收到警告:无法在未安装的组件上执行 React state 更新 - Getting Warning: Can't perform a React state update on an unmounted component 组件内部反应 state 更新未安装的组件 - Component inner react state update on an unmounted component 修复“无法对卸载的组件执行 React 状态更新”错误 - Fix "Can't perform a React state update on an unmounted component" error 无法对卸载的组件错误执行反应状态更新 - Can't perform a react state update on an unmounted component error 无法对未安装的组件 useEffect 错误执行 React state 更新 - Can't perform a React state update on an unmounted component useEffect error 错误:无法在未安装的组件上执行 React state 更新 - Error : Can't perform a React state update on an unmounted component
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM