When I transition to this screen, it will do some API calls to fetch the latest data. But it seems not trigger the didFocus event to fire the api calls when I transition from another navigation stack with hooks version while it works well with class version.
How do I make hooks version have the same behavior as class version?
What's the difference between this two version?
class someScreen extends Component {
componentDidMount() {
const {
navigation,
} = this.props;
this.navFocusListener = navigation.addListener('didFocus', () => {
// do some API calls here
console.log("class version");
API_CALL();
});
}
componentWillUnmount() {
this.navFocusListener.remove();
}
}
transition from other navigation stack to this screen: class version
transition between screens in same stack: class version
const someScreen = ({
navigation,
}) => {
useEffect(() => {
const navFocusListener = navigation.addListener('didFocus', () => {
// do some API calls here
API_CALL();
console.log('hooooks');
});
return () => {
navFocusListener.remove();
};
}, []);
}
transition from other navigation stack to this screen: nothing is shown in console
transition between screens in same stack: hooooks
BTW, here is the workaround solution I found
const someScreen = ({
navigation,
}) => {
useEffect(() => {
const isFocused = navigation.isFocused();
// manually judge if the screen is focused
// if did, fire api call
if (isFocused) {
// do the same API calls here
API_CALL();
console.log('focused section');
}
const navFocusListener = navigation.addListener('didFocus', () => {
// do some API calls here
API_CALL();
console.log('listener section');
});
return () => {
navFocusListener.remove();
};
}, []);
}
console output
transition from other navigation stack to this screen: focused section
transition between screens in same stack: listener section
The useFocusEffect is analogous to React's useEffect hook. The only difference is that it only runs if the screen is currently focused. The effect will run whenever the dependencies passed to React.
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.
To use the addEventListener method in function components in React: Set the ref prop on the element. Use the current property on the ref to get access to the element. Add the event listener in the useEffect hook.
navigation.addListener Inside a screen, you can add listeners on the navigation prop with the addListener method. The addListener method takes 2 arguments: type of the event, and a callback to be called on the event. It returns a function that can be called to unsubscribe from the event.
I guess I found the root cause of the inconsistent behavior. There is another hook called useLayoutEffect
useLayoutEffect The signature is identical to useEffect, but it fires synchronously after all DOM mutations. Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint.
the useLayoutEffect will block the painting while the useEffect will not. That confirm and explains my guess that the didFocus event had fired, but it didn't trigger the listener since it miss the timing
so in my case, I have to use useLayoutEffect instead of useEffect
reference: https://kentcdodds.com/blog/useeffect-vs-uselayouteffect https://reactjs.org/docs/hooks-reference.html#uselayouteffect
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With