react-navigation: Detect when screen, tabbar is activated / appear / focus / blur
Solution 1:
React navigation v6
Fetching data with an API call when a screen becomes focused
React Navigation provides a hook that runs an effect when the screen comes into focus and cleans it up when it goes out of focus. This is useful for cases such as adding event listeners, for fetching data with an API call when a screen becomes focused, or any other action that needs to happen once the screen comes into view.
import { useFocusEffect } from '@react-navigation/native';
function ProfileScreen() {
useFocusEffect(
React.useCallback(() => {
alert('Screen was focused');
return () => {
alert('Screen was unfocused');
// Useful for cleanup functions
};
}, [])
);
return <View />;
}
A boolean indicating whether the screen is focused or not
React Navigation provides a hook that returns a boolean indicating whether the screen is focused or not. The hook will return true when the screen is focused and false when our component is no longer focused. This enables us to render something conditionally based on whether the user is on the screen or not.
import { useIsFocused } from '@react-navigation/native';
function Profile() {
const isFocused = useIsFocused();
return <Text>{isFocused ? 'focused' : 'unfocused'}</Text>;
}
Ref v6.x: https://reactnavigation.org/docs/function-after-focusing-screen/
Older:
With react-navigation
, you can do that in 2 steps:
-
Add listeners in
componentDidMount
orcomponentWillMount
, to hook events -
Remove listeners in
componentWillUnmount
, to avoid unexpected calling
API Reference Documents v3.x, v4.x, v5.x
React-navigation v3.x, v4.x:
addListener
- Subscribe to updates to navigation lifecycleReact Navigation emits events to screen components that subscribe to them:
willFocus
- the screen will focusdidFocus
- the screen focused (if there was a transition, the transition completed)willBlur
- the screen will be unfocuseddidBlur
- the screen unfocused (if there was a transition, the transition completed)
React-navigation 3.x, 4.x example:
const didBlurSubscription = this.props.navigation.addListener(
'didBlur',
payload => {
console.debug('didBlur', payload);
}
);
// Remove the listener when you are done
didBlurSubscription.remove();
Ref v4.x https://reactnavigation.org/docs/4.x/navigation-prop/#addlistener---subscribe-to-updates-to-navigation-lifecycle
UPDATED v5.x
The events had been changed in v5.x
Screens can add listeners on the navigation prop like in React Navigation. By default, there are 2 events available:
- focus - This event is emitted when the screen comes into focus
- blur - This event is emitted when the screen goes out of focus
- state (advanced) - This event is emitted when the navigator's state changes
Sample code from reactnavigation.org
class Profile extends React.Component {
componentDidMount() {
this._unsubscribe = navigation.addListener('focus', () => {
// do something
});
}
componentWillUnmount() {
this._unsubscribe();
}
render() {
// Content of the component
}
}
Use with hook
function Profile({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// do something
});
return unsubscribe;
}, [navigation]);
return <ProfileContent />;
}
Listeners prop on Screen
<Tab.Screen
name="Chat"
component={Chat}
listeners={({ navigation, route }) => ({
tabPress: e => {
// Prevent default action
e.preventDefault();
// Do something with the `navigation` object
navigation.navigate('AnotherPlace');
},
})}
/>
Ref v5.x: https://reactnavigation.org/docs/navigation-events
Solution 2:
FOR V3.x and V4.x This might be late but this is how I solved it. See the code below. Don't forget to import withNavigation and wrap your export default withNavigation.
import { withNavigation } from "react-navigation";
componentDidMount() {
const { navigation } = this.props;
this.focusListener = navigation.addListener("didFocus", () => {
// The screen is focused
// Call any action
});
}
componentWillUnmount() {
// Remove the event listener
this.focusListener.remove();
}
export default withNavigation(Your Class Name);
FOR V5.x Please use this.
componentDidMount(){
const { navigation } = this.props;
this.focusListener = navigation.addListener("focus", () => {
// Call ur function here.. or add logic.
});
}
Solution 3:
componentDidMount
/ componentWillUnmount
does not work in all cases of navigation (like tabs).
You need to use addListener
with events didFocus and didBlur to make such actions. See documentation for details
Solution 4:
The latest version of react-navigation
provides custom hooks that let you react to focus and blur events: https://reactnavigation.org/docs/function-after-focusing-screen.
The following is an example from their docs that uses the onFocusEffect
hook to make an API call on focus (it cleans up the effect when the screen goes out of focus):
import { useFocusEffect } from '@react-navigation/native';
function Profile({ userId }) {
const [user, setUser] = React.useState(null);
useFocusEffect(
React.useCallback(() => {
const unsubscribe = API.subscribe(userId, user => setUser(data));
return unsubscribe;
}, [userId])
);
return <ProfileContent user={user} />;
}
Solution 5:
NavigationEvents
is another way to add event listener just inside JSX. See documentation for details.
It looks something like this:
import { NavigationEvents } from 'react-navigation';
return (
<ScrollView style={styles.container}>
<NavigationEvents
onDidBlur={payload => console.log('did blur', payload)}
/>
{this.props.children}
</ScrollView>
);