我的测试代码出现了很多错误,因此采取了一些措施来进行改进。本文有助于:https://binarapps.com/blog/clean-up-request-in-useeffect-react-hook/woodb
我通过引入AbortController改进了我怀疑是问题的useEffect
:
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]);
我还这样重构了测试代码:
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();
});
});
注意: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
};
}
根据oemera的问题,这是异步调用:
export const get = async function(url: string, _options: any) {
const options = _options || await _default_options();
return axios.get(url, options);
};
此重构后,错误/警告有所减少,但仍然出现以下情况:
> 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.
我已经检查了所有提到的代码AddUsers...
文件,但是那里没有useEffect
实例。
有关我应该如何删除此警告的任何建议?
答案 0 :(得分:2)
当您使用axios
而不是fetch
时,异常中止控制器将无法工作。这是您在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>
)
}
}
来源: https://gist.github.com/adeelibr/d8f3f8859e2929f3f1adb80992f1dc09
请注意如何传递cancelToken
而不是整个信号。另外,您可以使用axios.CancelToken.source()
来获得信号,然后调用signal.cancel
或abortController.abort
因此,在您的示例中,这应该像这样工作或至少将您引向正确的方向:
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]);