web-dev-qa-db-fra.com

Comment seinerval pour chaque deuxième rendu de 5 secondes avec React Hook useeffect In React Application natif?

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>
  )
}

6
jocoders

Cela pourrait être ces deux choses:

  • Vous devez effacer votre intervalle
  • Vous n'avez pas besoin de ne pas mettre à jour l'état de votre rappel de l'API si sa démonte.

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 ...).

2
denislexic