Learn about different techniques to delay running the code when the app is in the foreground or the background.
When building an application, much of your code will run in response to events like component lifecycle events and user interactions. Sometimes you'll need to delay when your code runs instead of running it immediately after an event. Responsive applications need to respond quickly to user interactions and render smooth animations, but the code for your user interface (such as React components that update the UI) shares a JS thread with other event-handling code. Therefore, you should be careful to schedule work in small increments and at times that won't impact your users' experience to deliver a great experience to your users.
While your application is in the foreground, you have access to scheduling functions that are often available in other JS environments like setTimeout
, setInterval
, and requestAnimationFrame
. If you are not familiar with these methods or when you might use them we recommend Mozilla's guide on asynchronous JavaScript.
React Native provides an additional timing technique with InteractionManager. InteractionManager allows you to schedule computationally expensive code to run after any interactions and animations they might impact have completed. You can schedule computations to run with InteractionManager.runAfterInteractions(() => { /* your task */ })
.
React Native itself, and high-quality libraries you might use, already register animations with InteractionManager
. If you need to, you can:
InteractionManager.createInteractionHandle()
on the start of your animationInteractionManager.clearInteractionHandle(resultOfCallToCreateInteractionHandle)
You may need to update a component's state at the end of your computation. A few points to note:
componentWillUnmount
lifecycle method.setState
when your computation is run.setState
is asynchronous, so if you need to mutate the existing state, pass a function rather than an object to the method.import React, { useState, useEffect } from 'react';
import { Text } from 'react-native';
const App = () => {
// Set the initial count to 0
const [count, setCount] = useState(0);
useEffect(() => {
// increment the count by 1
const countTimer = setInterval(() => {
setCount((prevCount) => prevCount + 1);
// every 1000 milliseconds
}, 1000);
// and clear this timer when the component is unmounted
return function cleanup() {
clearInterval(countTimer);
};
});
return (<Text>Count is {count}</Text>);
};
export default App;
import React from 'react';
import { Text } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
componentDidMount() {
this.timer = setInterval(() => {
this.setState((state) => ({ count: state.count + 1 }));
}, 1000);
}
componentWillUnmount() {
clearInterval(this.timer);
}
render() {
return <Text>Count is {this.state.count}</Text>;
}
}
For some use cases, you want your computation to continue even while your user switches to another app. Setting this up manually can be complex, so Expo provides some modules that simplify things for the most common use cases.
If you want to... | You can use... |
---|---|
fetch data from some endpoint | expo-background-fetch |
respond to changes in the user's location | expo-location |
perform a generic long-running computation | expo-task-manager |