How to setInterval for every 5 second render with React hook useEffect in React Native app?
Solution 1
You need to clear your interval
,
useEffect(() => {
const intervalId = setInterval(() => { //assign interval to a variable 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 => 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
}, [url, useState])
For more about cleanup
functions in useEffect
refer to this.
Solution 2
It might be both these things:
- You need to clear up your interval
- You need to not update state from your API callback if its unmounted.
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])
Might want, depending on your server response time, add a failsafe for pending queries (example, if you sent out a query and the next one launches before the first one returns...).
Solution 3
For React Hooks + Apollo to fetch data from a GraphQL server every 5 seconds. In this example, we logout the user in React if the user is not logged-in in the backend. (JWT token not valide anymore)
import React from 'react'
import gql from 'graphql-tag'
import { useApolloClient } from '@apollo/react-hooks'
export const QUERY = gql`
query Me {
me {
id
}
}
`
const MyIdle = () => {
const client = useApolloClient()
React.useEffect(() => {
async function fetchMyAPI() {
try {
await client.query({
query: QUERY,
fetchPolicy: 'no-cache',
})
} catch (e) {
// Logout the user and redirect to the login page
}
}
const intervalId = setInterval(() => {
fetchMyAPI()
}, 1000 * 5) // in milliseconds
return () => clearInterval(intervalId)
}, [client])
return null
}
export default MyIdle
![jocoders](https://i.stack.imgur.com/gytCX.jpg?s=256&g=1)
jocoders
💠My passion is to build high quality mobile apps 📱with React Native, TypeScript & MobX.
Updated on December 27, 2021Comments
-
jocoders over 2 years
I have
React Native
app and I get data fromAPI
byfetch
. I created custom hook that get data fromAPI
. And i need to re-render it every 5 seconds. For it I wrapped my custom hook to setInterval and after my app become work very slowly and when I navigate to another screen I get this error: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.
Can you tell me please how can I solve this bug and which will be the best way to
setInterval
, because I think my way is not good.My custom hook:
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 }
My Component:
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> ) }