I want to dispatch a action when drawer close.But I don't know I need write what function, can you help me.
You need to custom navigation actions to know when the DrawerClose event fired.Here is a simple example:
const MyAppDrawerNavigator = DrawerNavigator({
//...
});
const defaultGetStateForAction = MyAppDrawerNavigator.router.getStateForAction;
MyAppDrawerNavigator.router.getStateForAction = (action, state) => {
if (state && action.type === 'Navigation/NAVIGATE' && action.routeName === 'DrawerClose') {
console.log('DrawerClose');
//dispatch whatever action you want
}
return defaultGetStateForAction(action, state);
};
To known more about how to custom routers, see here.
Related
how to pass parameters in pop method.
Requirement: There are two screens, screen 1 has two tabs like this: Address and Billing. There are two button on each tab layout. On click button go to screen 2 after functionality back to screen 1 but now which tab is active. If go to address tab so back to address tab same as billing tab.
Tell me how to do it?
You can pass callback while pushing screen like
Navigation.push(this.props.componentId, {
component: {
name: "Your.ScreenName",
options: {
callback:this.yourCallBackFun
}
}
});
Now while pop you can call that function like
this.props.callback();
Navigation.pop(this.props.componentId);
I think it will help you.
Screen A:
this.props.navigation.navigate('ScreenB', {func: this.func});
...
func = value => {
console.log(value);
}
Screen B:
this.props.navigation.getParam('func')();
You can call ScreenA function like this.
Screen1:
Write your navigation function and callback function in your first screen.
Pass callback function as a navigation parameter white pushing the screen.
const cbFunction = () => new Promise((resolve) => {
resolve();
});
const navigation = () => {
const { componentId } = this.props;
Navigation.push(componentId, {
component: {
name: `SCREEN_NAME`,
options: {
cbFunction: this.cbFunction
}
}
});
}
Screen2:
Write a function to go back to first screen. And call callback function from navigation parameter.
const goBack = async () => {
const { cbFunction, componentId } = this.props;
await cbFunction();
Navigation.pop(componentId);
}
As the docs https://reactnavigation.org/docs/en/next/use-focus-effect.html,
"Sometimes we want to run side-effects when a screen is focused. A side effect may involve things like adding an event listener, fetching data, updating document title, etc."
I'm trying to use useFocusEffect to fetch data everytime that the user go to that page.
on my component I have a function which dispatch an action with redux to fetch the data:
const fetchData = ()=>{
dispatch(companyJobsFetch(userDetails.companyId));
};
Actually I'm using useEffect hook to call fetchData(), but I'd like to fetch data everytime that the user go to that page and not only when rendered the first time.
It's not clear from the documentation how to use useFocusEffect and I'm not having success on how to do it.
Any help?
The docs show you how to do it. You need to replace API.subscribe with your own thing:
useFocusEffect(
React.useCallback(() => {
dispatch(companyJobsFetch(userDetails.companyId));
}, [dispatch, companyJobsFetch, userDetails.companyId])
);
For version react navigation 4.x, you can use addEvent listener
useEffect(() => {
if (navigation.isFocused()) {
resetReviews(); // replace with your function
}
}, [navigation.isFocused()]);
OR
useEffect(() => {
const focusListener = navigation.addListener('didFocus', () => {
// The screen is focused
// Call any action
_getBusiness({id: business?.id}); // replace with your function
});
return () => {
// clean up event listener
focusListener.remove();
};
}, []);
For later version 5.x, you can use hooks to achieve this
import { useIsFocused } from '#react-navigation/native';
// ...
function Profile() {
const isFocused = useIsFocused();
return <Text>{isFocused ? 'focused' : 'unfocused'}</Text>;
}
I have a navigation like so:
Loading: SwitchNavigator {
Auth: Stacknavigator,
Main: StackNavigator,
Onboard: StackNavigator,
}
every one of StackNavigators has an initial route set. Under certain circumstances, I want to go from loading navigator to a specific route on onboard navigator. If I use just navigator.navigate('DesiredRoute'), it squeezes in also onboard's initialRoute, so the navstack looks like [InitialRoute, DesiredRoute] instead of [DesiredRoute]. How to get rid of the InitialRoute?
Code example:
// Loading.js
if (loadingComplete) {
if (!user) {
navigation.navigate('auth')
return
}
if (user && userData) {
navigation.navigate('Main')
return
}
if (onboardingCheckpointCleared) {
// this creates `['InitialRoute', 'DesiredRoute']` instead of `['DesiredRoute']`
navigation.navigate('DesiredRoute')
return
}
navigation.navigate('Onboard')
}
This is expected behavior, if you want only DesiredRoute to appear then you have to set that route in Loading as well like below,
Loading: SwitchNavigator {
Auth: Stacknavigator,
Main: StackNavigator,
Onboard: StackNavigator,
DesiredRoute: ScreenName
}
Writing like this will not create any clash, you are safe to write.
I assume you are navigating to DesiredRoute from outside the Onboard stack navigator
If you're outside the Onboard navigator, doing navigation.navigate('DesiredRoute') will trigger two actions: first, it will navigate to the Onboard stack navigator (so it will also activate the default sub screen of it InitialRoute like you call it) and then it will push the DesiredRoute. If you want to go to Onboard with only DesiredRoute on the stack, you can use the sub actions of the navigation actions like this:
navigation.navigate('Onboard', undefined, StackActions.replace('DesiredRoute'));
The third argument is an action that can be will be executed by the first argument navigator (if the first argument is not a screen but a navigator). Here it will navigate to the Onboard navigator and thus put the InitialRoute in the stack (automatically as it's the initialRoute of Onboard). However, the StackAction.replace('DesiredRoute') will be executed by the Onboard navigator and will replace InitialRoute with DesiredRoute.
See the official doc about the navigate: https://reactnavigation.org/docs/en/navigation-prop.html#navigate-link-to-other-screens
I ended up creating a custom router that strips out the initial route when navigating to my nested stack:
const MyStackNav = createStackNavigator({ ...routes })
const defaultGetStateForAction = MyStackNav.router.getStateForAction
const customGetStateForAction = (action, state) => {
const defaultNavState = defaultGetStateForAction(action, state)
// If we're pushing onto a stack that only has a defaulted initialRoute
if (
!!defaultNavState &&
!defaultNavState.routeName &&
defaultNavState.isTransitioning &&
defaultNavState.index === 1 &&
action.type === NavigationActions.NAVIGATE
) {
const newState = {
...defaultNavState,
index: 0, // Decrement index
routes: defaultNavState.routes.slice(1), // Remove initial route
}
return newState
}
return defaultNavState
}
I want to call a class function on drawer open and drawer close event can any one help me with this as i am new at react native.
const defaultGetStateForAction =Drawer.router.getStateForAction;
Drawer.router.getStateForAction = (action, state) => {
if(state && action.type === 'Navigation/OPEN_DRAWER' ) {
Alert.alert("drawerOpen")
//here call a class function with true value
}
if(state && action.type === 'Navigation/DRAWER_CLOSED') {
Alert.alert("drawerClose")
//here call a class function with false value
}
Use the below code to solve your problem
When press on any button on my React Native App to navigate to a different screen multiple times, then it will redirected to the next screen multiple times.
My sample code is:
// This is my button click event
myMethod()
{
this.props.navigation.navigate("ScreenName")
}
I am using react-navigation to navigate through my app.
How can I fix this behaviour?
I think there are a few ways this could be done. Perhaps recording when the navigation has occurred and preventing it from navigating multiple times.
You may also want to consider resetting hasNavigated after an amount of time etc as well.
// Somewhere outside of the myMethod scope
let hasNavigated = false
// This is my button click event
myMethod()
{
if (!hasNavigated) {
this.props.navigation.navigate("ScreenName")
hasNavigated = true
}
}
This react-navigation issue contains a discussion about this very topic, where two solutions were proposed.
The first, is to use a debouncing function such as Lodash's debounce that would prevent the navigation from happening more than once in a given time.
The second approach, which is the one I used, is to check on a navigation action, whether it is trying to navigate to the same route with the same params, and if so to drop it.
However, the second approach can only be done if you're handling the state of the navigation yourself, for example by using something like Redux.
Also see: Redux integration.
One of solution is custom custom components with adds debounce to onPress:
class DebounceTouchableOpacity extends Component {
constructor(props) {
super(props);
this.debounce = false;
}
_onPress = () => {
if (typeof this.props.onPress !== "function" || this.debounce)
return;
this.debounce = true;
this.props.onPress();
this.timeoutId = setTimeout(() => {
this.debounce = false;
}, 2000);
};
componentWillUnmount() {
this.timeoutId && clearTimeout(this.timeoutId)
}
render() {
const {children, onPress, ...rest} = this.props;
return (
<TouchableOpacity {...rest} onPress={this._onPress}>
{children}
</TouchableOpacity>
);
}
}
another: wrap onPress function into wrapper with similar behavior
const debounceOnPress = (onPress, time) => {
let skipCall = false;
return (...args) => {
if (skipCall) {
return
} else {
skipCall = true;
setTimeout(() => {
skipCall = false;
}, time)
onPress(...args)
}
}
}