J'ai React Native
Et je reçois des données de API
par fetch
. J'ai créé un crochet personnalisé qui obtienne des données de API
. Et j'ai besoin de le rendant chaque 5 secondes. Pour cela, j'ai enveloppé mon crochet personnalisé à seinterval et après que mon application soit devenue un travail très lentement et lorsque je navigue sur un autre écran, je reçois cette erreur:
Impossible d'effectuer une mise à jour de l'état React sur un composant non monté. Ceci est un non-op, mais cela indique une fuite de mémoire dans votre application. Pour résoudre, annulez tous les abonnements et les tâches asynchrones dans une fonction d'usage de nettoyage UseEffect.
Pouvez-vous me dire s'il vous plaît comment puis-je résoudre ce bogue et qui sera le meilleur moyen de setInterval
, car je pense que mon chemin n'est pas bon.
mon crochet personnalisé :
export const useFetch = url => {
const [state, setState] = useState({ data: null, error: false, loading: true })
useEffect(() => {
setInterval(() => {
setState(state => ({ data: state.data, error: false, loading: true }))
fetch(url)
.then(data => data.json())
.then(obj =>
Object.keys(obj).map(key => {
let newData = obj[key]
newData.key = key
return newData
})
)
.then(newData => setState({ data: newData, error: false, loading: false }))
.catch(function(error) {
console.log(error)
setState({ data: null, error: true, loading: false })
})
}, 5000)
}, [url, useState])
useEffect(() => () => console.log('unmount'), [])
return state
}
mon composant :
const ChartsScreen = ({ navigation }) => {
const { container } = styles
const url = 'https://poloniex.com/public?command=returnTicker'
const { data, error, loading } = useFetch(url)
const percentColorHandler = number => {
return number >= 0 ? true : false
}
return (
<View style={container}>
<ProjectStatusBar />
<IconsHeader
dataError={false}
header="Charts"
leftIconName="ios-arrow-back"
leftIconPress={() => navigation.navigate('Welcome')}
/>
<ChartsHeader />
<ActivityIndicator animating={loading} color="#068485" style={{ top: HP('30%') }} size="small" />
<FlatList
data={data}
keyExtractor={item => item.key}
renderItem={({ item }) => (
<CryptoItem
name={item.key}
highBid={item.highestBid}
lastBid={item.last}
percent={item.percentChange}
percentColor={percentColorHandler(item.percentChange)}
/>
)}
/>
</View>
)
}
Cela pourrait être ces deux choses:
Code:
useEffect(() => {
let isMounted = true
const intervalId = setInterval(() => { //assign interval to a variaable to clear it
setState(state => ({ data: state.data, error: false, loading: true }))
fetch(url)
.then(data => data.json())
.then(obj =>
Object.keys(obj).map(key => {
let newData = obj[key]
newData.key = key
return newData
})
)
.then(newData => {
if(!isMounted) return // This will cancel the setState when unmounted
setState({ data: newData, error: false, loading: false })
})
.catch(function(error) {
console.log(error)
setState({ data: null, error: true, loading: false })
})
}, 5000)
return () => {
clearInterval(intervalId); //This is important
isMounted = false // Let's us know the component is no longer mounted.
}
}, [url, useState])
Peut-être souhaiter, en fonction de votre temps de réponse du serveur, ajoutez un échec sur les requêtes en attente (exemple, si vous avez envoyé une requête et que le prochain lancé avant le premier retourner ...).