Javascript 在React功能组件中取消异步axios请求的正确方法
在React功能组件中取消异步请求的正确方法是什么? 我有一个脚本,在加载时(或在某些用户操作下)从API请求数据,但如果正在执行此脚本&用户导航离开,则会导致以下警告: 警告:无法对已卸载的组件执行React状态更新。这是一个no-op,但它表示应用程序中存在内存泄漏。要修复此问题,请取消useEffect清理函数中的所有订阅和异步任务 我所读的大部分内容都是通过基于类的组件的Javascript 在React功能组件中取消异步axios请求的正确方法,javascript,reactjs,axios,Javascript,Reactjs,Axios,在React功能组件中取消异步请求的正确方法是什么? 我有一个脚本,在加载时(或在某些用户操作下)从API请求数据,但如果正在执行此脚本&用户导航离开,则会导致以下警告: 警告:无法对已卸载的组件执行React状态更新。这是一个no-op,但它表示应用程序中存在内存泄漏。要修复此问题,请取消useEffect清理函数中的所有订阅和异步任务 我所读的大部分内容都是通过基于类的组件的componentdidumount方法中的AbortController来解决这个问题的。然而,我的React应用程
componentdidumount
方法中的AbortController
来解决这个问题的。然而,我的React应用程序中有一个功能组件,它使用Axis向API发出异步数据请求
该函数位于功能组件中的useffect
钩子中,以确保在组件呈现以下内容时运行该函数:
useffect(()=>{
加载字段();
},[loadFields]);
这是它调用的函数:
const loadFields = useCallback(async () => {
setIsLoading(true);
try {
await fetchFields(
fieldsDispatch,
user.client.id,
user.token,
user.client.directory
);
setVisibility(settingsDispatch, user.client.id, user.settings);
setIsLoading(false);
} catch (error) {
setIsLoading(false);
}
}, [
fieldsDispatch,
user.client.id,
user.token,
user.client.directory,
settingsDispatch,
user.settings,
]);
这是触发的axios请求:
async function fetchFields(dispatch, clientId, token, folder) {
try {
const response = await api.get(clientId + "/fields", {
headers: { Authorization: "Bearer " + token },
});
// do something with the response
} catch (e) {
handleRequestError(e, "Failed fetching fields: ");
}
}
注意:api
变量是对axios.create
对象的引用。有一个可以使用的返回选项。它的行为(几乎)与componentDidUnmount相同
useEffect(() => {
// Your axios call
return () => {
// Your abortController
}
}, []);
有一个您可以使用的返回选项。它的行为(几乎)与componentDidUnmount相同
useEffect(() => {
// Your axios call
return () => {
// Your abortController
}
}, []);
您可以使用lodash.debounce并尝试以下步骤 Stap 1:
inside constructor:
this.state{
cancelToken: axios.CancelToken,
cancel: undefined,
}
this.doDebouncedTableScroll = debounce(this.onScroll, 100);
步骤2:
使用axios add的内部函数:
if (this.state.cancel !== undefined) {
cancel();
}
步骤3:
onScroll = ()=>{
axiosInstance()
.post(`xxxxxxx`)
, {data}, {
cancelToken: new cancelToken(function executor(c) {
this.setState({ cancel: c });
})
})
.then((response) => {
}
您可以使用lodash.debounce并尝试以下步骤 Stap 1:
inside constructor:
this.state{
cancelToken: axios.CancelToken,
cancel: undefined,
}
this.doDebouncedTableScroll = debounce(this.onScroll, 100);
步骤2:
使用axios add的内部函数:
if (this.state.cancel !== undefined) {
cancel();
}
步骤3:
onScroll = ()=>{
axiosInstance()
.post(`xxxxxxx`)
, {data}, {
cancelToken: new cancelToken(function executor(c) {
this.setState({ cancel: c });
})
})
.then((response) => {
}
要使用
axios
取消fetch
操作:
广告1。)
axios
带来了自己的取消API:
const source = axios.CancelToken.source();
axios.get('/user/12345', { cancelToken: source.token })
source.cancel(); // invoke to cancel request
您可以使用它通过停止一个异步请求来优化性能,这已经不再需要了。如果使用本机浏览器fetch
API,则将改用
广告2。)
这将停止警告“警告:无法对未安装的组件执行React状态更新。”
。例如,不能对已卸载的组件调用setState
。是一个执行和封装上述约束的钩子示例
示例:
useAxiosFetch
我们可以将这两个步骤合并到自定义挂钩中:
function useAxiosFetch(url, { onFetched, onError, onCanceled }) {
React.useEffect(() => {
const source = axios.CancelToken.source();
let isMounted = true;
axios
.get(url, { cancelToken: source.token })
.then(res => { if (isMounted) onFetched(res); })
.catch(err => {
if (!isMounted) return; // comp already unmounted, nothing to do
if (axios.isCancel(err)) onCanceled(err);
else onError(err);
});
return () => {
isMounted = false;
source.cancel();
};
}, [url, onFetched, onError, onCanceled]);
}
从“React”导入React;
从“axios”导入axios;
导出默认函数App(){
const[mounted,setMounted]=React.useState(true);
返回(
{挂载&&}
setMounted(p=>!p)}>
{装载?“卸载”:“装载”}
);
}
常数Comp=()=>{
const[state,setState]=React.useState(“加载…”);
常量url=`https://jsonplaceholder.typicode.com/users/1?_delay=3000×tamp=${new Date().getTime()}`;
const handlers=React.usemo(
() => ({
onFetched:res=>setState(`Fetched user:${res.data.name}`),
onCanceled:err=>setState(“请求已取消”),
onError:err=>setState(“其他错误:”,err.message)
}),
[]
);
const cancel=useAxiosFetch(url,处理程序);
返回(
{state}
{state==“正在加载…”&&(
取消请求
)}
);
};
//您可以使用自定义配置参数扩展此挂钩,以获得更多axios选项
函数useAxiosFetch(url,{onFetched,onError,onCanceled}){
const cancelRef=React.useRef();
const cancel=()=>cancelRef.current&&cancelRef.current.cancel();
React.useffect(()=>{
cancelRef.current=axios.CancelToken.source();
让isMounted=真;
axios
.get(url,{cancelToken:cancelRef.current.token})
。然后(res=>{
如果(isMounted)已获取(res);
})
.catch(错误=>{
如果(!isMounted)return;//comp已卸载,则无需执行任何操作
如果(axios.isCancel(err))被取消(err);
其他错误(err);
});
return()=>{
isMounted=错误;
取消();
};
},[url,onFetched,onError,onCanceled];
返回取消;
}
要取消使用axios的获取操作
:
具有给定源令牌的请求
请确保在卸载组件后不会更改组件状态
广告1。)
axios
带来了自己的取消API:
const source = axios.CancelToken.source();
axios.get('/user/12345', { cancelToken: source.token })
source.cancel(); // invoke to cancel request
您可以使用它通过停止一个异步请求来优化性能,这已经不再需要了。如果使用本机浏览器fetch
API,则将改用
广告2。)
这将停止警告“警告:无法对未安装的组件执行React状态更新。”
。例如,不能对已卸载的组件调用setState
。是一个执行和封装上述约束的钩子示例
示例:useAxiosFetch
我们可以将这两个步骤合并到自定义挂钩中:
function useAxiosFetch(url, { onFetched, onError, onCanceled }) {
React.useEffect(() => {
const source = axios.CancelToken.source();
let isMounted = true;
axios
.get(url, { cancelToken: source.token })
.then(res => { if (isMounted) onFetched(res); })
.catch(err => {
if (!isMounted) return; // comp already unmounted, nothing to do
if (axios.isCancel(err)) onCanceled(err);
else onError(err);
});
return () => {
isMounted = false;
source.cancel();
};
}, [url, onFetched, onError, onCanceled]);
}
从“React”导入React;
从“axios”导入axios;
导出默认函数App(){
const[mounted,setMounted]=React.useState(true);
返回(
{挂载&&}
setMounted(p=>!p)}>
{装载?“卸载”:“装载”}
);
}
常数Comp=()=>{
const[state,setState]=React.useState(“加载…”);
常量url=`https://jsonplaceholder.typicode.com/users/1?_delay=3000×tamp=${new Date().getTime()}`;
const handlers=React.usemo(
() => ({
onFetched:res=>setState(`Fetched user:${res.data.name}`),
onCanceled:err=>setState(“请求已取消”),
onError:err=>setState(“其他错误:”,err.message)
}),
[]
);
const cancel=useAxiosFetch(url,处理程序);
返回(
{state}
{state==“正在加载…”