我在我的 spotify api 应用程序中使用 react-native,当我想使用 axios
从我的服务器获取数据时(在 useEffect
中,因为我想在组件加载时呈现返回的项目)它抛出错误: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
。所以如果有人知道如何解决这个问题,我会非常感激。
import React, {useEffect, useState} from 'react'
import { View, Text, StyleSheet, Image, FlatList, ActivityIndicator} from 'react-native'
import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage';
export default function ArtistsCom({route}) {
const type = route.name.toLowerCase();
const [time, setTime] = useState('short_term');
const [access_token, setAccess_token] = useState('');
const [refresh_token, setRefresh_token] = useState('');
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
AsyncStorage.getItem('refresh_token')
.then(value => setRefresh_token(value));
const getDataAsync = async () => {
const res = await axios.post(`http://localhost:3001/api/refresh`, {
headers: {
body: {
refresh_token: refresh_token
}
}
})
console.log(res);
setAccess_token(res.data.access_token);
return res;
};
getDataAsync();
}, []);
return (
<View>
<View>
{!loading ? items.map((item, key) => {
return (
<View key={key} style={{width: 150, height: 150, margin: 10}}>
<Image style={{width: '100%', height: '100%'}} source={{uri: type == 'artists' ? item.images[0].url : item.album.images[0].url}} />
<View style={{position: 'absolute', bottom: 0, left:4, height: 20, width: '100%', backgroudColor: 'red'}}><Text style={{color: 'white'}}>{key+1}. {item.name}</Text></View>
</View>
)
}) : <Text>Loading...</Text>}
</View>
</View>
)
}
答案 0 :(得分:1)
您可以使用取消令牌来取消正在进行的请求。
useEffect(() => {
...
// Create cancel token and source
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
const getDataAsync = async () => {
const res = await axios.post(
`http://localhost:3001/api/refresh`,
{
cancelToken: source.token, // <-- attach cancel token to request
headers: {
body: {
refresh_token: refresh_token
}
}
},
);
console.log(res);
setItems(res.data.items);
return res;
};
getDataAsync();
// Return useEffect cleanup function to cancel request
return () => {
source.cancel('Component unmounted'); // message is optional
};
}, []);
将异步逻辑包含在 try/catch/finally
中以发出多个请求并处理任何被拒绝的承诺和错误。
useEffect(() => {
// Create cancel token and source
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
const getDataAsync = async () => {
setLoading(true);
try {
const refresh_token = await AsyncStorage.getItem('refresh_token');
const res = await axios.post(
`http://localhost:3001/api/refresh`,
{
cancelToken: source.token, // <-- attach cancel token to request
headers: {
body: {
refresh_token
}
}
},
);
const { access_token } = res.data;
setAccess_token(access_token);
const res2 = await axios.get(`http://localhost:3001/api/top/${type}?time_range=${time}&limit=50&access_token=${access_token}`);
setItems(res2.data.items);
} catch(error) {
// handle any errors, log them, set some state, etc...
} finally {
setLoading(false);
}
};
getDataAsync();
// Return useEffect cleanup function to cancel request
return () => {
source.cancel('Component unmounted'); // message is optional
};
}, [refreshToken]);
答案 1 :(得分:0)
我想通了
代码如下:
const type = route.name.toLowerCase();
const [time, setTime] = useState('short_term');
const [access_token, setAccess_token] = useState('');
const [refresh_token, setRefresh_token] = useState('');
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
const getItems = (ACCESS_TOKEN) => {
axios.get(`http://localhost:3001/api/top/${type}?time_range=${time}&limit=50&access_token=${ACCESS_TOKEN}`)
.then(res => {
setItems(res.data.items);
setLoading(false);
})
}
useEffect(() => {
setLoading(true);
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
const getRefreshedAccessToken = async() => {
axios.post(`http://localhost:3001/api/refresh`, {
cancelToken: source.token,
headers: {
body: {
refresh_token: await AsyncStorage.getItem('refresh_token')
}
}
})
.then(res => {
console.log(res.data.access_token);
setAccess_token(res.data.access_token);
getItems(res.data.access_token);
})
.catch(err => console.log(err))
};
getRefreshedAccessToken();
return () => {
source.cancel('Component unmounted');
}
}, [refresh_token]);