I want to prevent user from leaving screen before saving details by clicking on any item in drawer menu. I used this below snippet to prevent navigation. But issue is I've screens which are hidden in drawer menu so when I try to add drawerItemPress actions in those screens, it is not getting triggered.
useEffect(() => {
const unsubscribe = props.navigation.addListener('drawerItemPress', (e) => {
// Prevent default behaviour
console.log("props.saveTrigger")
if(rootStore.getState().transactionReducer.saveTrigger) {
console.log("stop navigation");
e.preventDefault();
}
else {
console.log("go ahead with navigation")
}
// Do something manually
// ...
});
return unsubscribe;
}, [props.navigation]);
Related
I am using bottom tab navigator in React-native for Navigation. When I switches tab, component are not updating.
Pls let me know how can I update/refresh whole component when I tap on tab at bottom Tab Navigator
Here is a simple solution.
import { useFocusEffect } from '#react-navigation/native';
useFocusEffect(
React.useCallback(() => {
console.log("Function Call on TAb change")
}, [])
);
Here is the link you can read more. https://reactnavigation.org/docs/function-after-focusing-screen/
You can use Navigation listener check Navigation Events, when screen gets focused it will trigger a function like this:
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
//Your refresh code gets here
});
return () => {
unsubscribe();
};
}, [navigation]);
And class component like this:
componentDidMount() {
this._unsubscribe = navigation.addListener('focus', () => {
//Your refresh code gets here
});
}
componentWillUnmount() {
this._unsubscribe();
}
If you want to force update check this question
I'm developing a social network, and I have the Home screen, where a feed is loaded and a Post screen.
How to trigger reloading only when a post is created?
Both screens are inside a Bottom Navigator.
if you wanna you components to be reloaded with states then you can use redux or react context.
but if you are not using those then you cannot reload but you can call function when tab is changed or pressed refer this https://reactnavigation.org/docs/bottom-tab-navigator/#events
and call your functions inside this to reload the data.
React.useEffect(() => {
const unsubscribe = navigation.addListener('tabPress', (e) => {
// Prevent default behavior
e.preventDefault();
// Do something manually
// ...
});
return unsubscribe;
}, [navigation]);
or even you can use focus method
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// do something
});
return unsubscribe;
}, [navigation]);
The React Navigation version I am using is v5. In the ScrollView corresponding to a Bottom Tab Icon, if the user is already on that given screen, I want to enable functionality where the user scrolls to the top when this icon is pressed.
As stated in the documentation, this feature should be already implemented. But I think you have placed your ScrollView inside a nested StackNavigator, right?
In that case, you probably need to subscribe to TabNavigator event and fire your scrollToTop manually
React.useEffect(() => {
const unsubscribe = navigation.addListener('tabPress', e => {
// Get your scrollView ref and dispatch scrollToTop
});
return unsubscribe;
}, [navigation]);
Hope it'll help you!
None of the solutions worked for me on the web, not using listener and not using useScrollToTop which is provided by react-navigation. Because I have nested stacks and navigators and also custom tabbar.
I solved the problem by setting a navigation param for scrolling to the top.
I have custom tabbar, and I needed to scroll to top on the homepage which was the first route of the tab stack.
So, in the homepage I set the scrollToTop parameter for the navigator:
const homelistRef = React.useRef<FlatList | null>(null)
useFocusEffect(
useCallback(() => {
navigation.setParams({
scrollToTop: () => homelistRef.current?.scrollToOffset({ offset: 0, animated: true }),
});
}, [navigation, homelistRef]),
);
return (
<FlatList
ref={homelistRef}
...{other Flatlist configs}
/>
)
And in my Tabbar component, I read this new param and execute it in the onPress function of the tabs:
interface IProps extends BottomTabBarProps {}
const TabBar: React.FC<IProps> = ({ state, navigation }) => {
const handleTabPress = useCallback(
(route) => async () => {
const currentRoute = state.routes?.[state.index];
if (
route === currentRoute?.name &&
state.routes?.[0].state?.routes?.[0]?.params?.scrollToTop
) {
state.routes[0].state.routes[0].params.scrollToTop();
}
},
[navigation, state],
);
return (
{render tab component}
)
}
And that's the ultimate solution for executing some action on active tabs.
As they point out in the docs, they've gotten rid of the 4 navigation event listeners and instead decided to use Lifecycle events.
But the problem I'm running into with React Navigation 5 is that the blur event doesn't work as I need it to! Before, I could add an onWillBlur listener, and do stuff when the user temporarily leaves (not closes) the app (such as close a socket connection, and then reopen it when the user reenters the app).
How can I replicate the onWillBlur or onDidBlur events for such a use case? I don't need to know if Screen A is blurred after the user is taken to Screen B after clicking a button.
You can use the hook useFocusEffect.
Documentation here
EDIT:
Added example from React Navigation.
import { useFocusEffect } from '#react-navigation/native';
function Profile() {
useFocusEffect(
React.useCallback(() => {
// Do something when the screen is focused, onFocus
return () => {
// Do something when the screen is unfocused, onBlur
// Useful for cleanup functions
};
}, [])
);
return <ProfileContent />;
}
EDIT 2:
I didn't test it on home button but I found a post that helps with that too
Check here
I hope this time you are pleased with my answer.
And here you have a working example :
import React from 'react'
import { Text, AppState } from 'react-native'
const MyComponent = () => {
const [appState, setAppState] = React.useState(AppState.currentState)
React.useEffect(() => {
AppState.addEventListener('change', handleChanges)
setAppState(AppState.currentState)
return AppState.removeEventListener('change')
},[])
const handleChanges = (nextAppState) => {
if (appState.match(/inactive|background/) && nextAppState === 'active') {
console.log('App has come to the foreground!');
} else {
console.log('App has gone to the background!');
// start your background task here
}
setAppState(nextAppState)
}
return <Text>{appState}</Text>
}
I develop a app use navigation drawer.that navigate screens use navigation drawer.but that screens are not refresh when navigate.how i fix this
Add the following code in your componentDidMount()
componentDidMount() {
this.subs = this.props.navigation.addListener("didFocus", () => {
//Your logic, this listener will call when you open the class every time }
);
}
And don't remember to remove listener in componentWillUnmount(),
componentWillUnmount() {
this.subs.remove();
}