Basically I have three screens, the first is a stack navigator:
const stackNav = createStackNavigator({
Main: {
screen: MainScreen,
navigationOptions:({navigation}) => ({
header: null,
})
},
Detail: {
screen: DetailScreen,
navigationOptions: (props) => ({
title: "Detail",
})
}
})
The second one I have a button to go to the Detail screen:
<TouchableOpacity onPress={() => this.props.navigation.navigate("Detail", {name: l.name, subtitle: l.subtitle})}>
The last one is just information, I would like to click a button and execute:
this.props.navigation.goBack(), but sending props to the second screen (MainScreen), a setState and a integer id, how can I do that?
--EDIT WITH PARAMS--
I have this function in MainScreen:
handleOrdem(texto) {
console.log('texto: '+texto)
this.setState({
param: global.ordemAtiva,
ordemAtiva: !this.state.ordemAtiva
});
}
//The onPress code:
onPress={() => this.props.navigation.navigate("Detail", {name: l.name, subtitle: l.subtitle, ordemFunc: () => this.handleOrdem()})}>
and this is how I call it in Detail.screen:
execBack(param){
console.log('param: '+param);
this.props.navigation.state.params.ordemFunc(param);
this.props.navigation.goBack();
}
//Button to do it
onPress={() => this.execBack('test')}
Create a Method in parent screen
returnData(){
PERDROM_EVENT_WITH_RECEIVED_DATA
}
Then bind this method returnData with navigation code while executing navigation code
this.props.navigation.navigate("Detail", {name: l.name, subtitle: l.subtitle , returnData: this.returnData.bind(this)})}
In child Component call returnData method before call of goBack()
this.props.navigation.state.params.returnData(RETURN_DATA_YOU_WANT);
this.props.navigation.goBack();
Handling return data
Suppose you want two parameters back then add two parms in returnData() method
For example we took first param is boolean and second param String
returnData(flag,id){
USE THIS `flag` and `id` to update state or method call or
What ever you wanted too.
}
And inside Child component pass these two param
this.props.navigation.state.params.returnData(VALUE_OF `flag`, Value of `id`);
FOR EDIT WITH PARAMS
replace your code of navigation with this line
this.props.navigation.navigate("Detail", {name: l.name, subtitle: l.subtitle, ordemFunc: this.handleOrdem.bind(this)})>
You have to bind method not to call with arrow function
So the problem is
ordemFunc: () => this.handleOrdem()
Replace this line with
ordemFunc: this.handleOrdem.bind(this)
I came across this exact same issue and the problem is actually quite simple. We will utilise a callback for passing the params when we trigger goBack()
For example lets say I have two Views: ViewA and ViewB.
For which I will do as follows:
import useNavigation hook for setting up navigation.
When navigating to the next screen pass a callback ie: function with the specified paramaters for the values you would like to pass back to ViewA.
In ViewB use the route prop to get access to the params. In here you will find your callback.
Use your callback and pass in the correct arguments to your callback.
Call the navigation.goBack() to return to ViewA
In ViewA you will now have access to your value in your callback.
import React from "react";
import { View, Button } from "react-native";
import { useNavigation } from "#react-navigation/native";
const ViewA = () => {
const navigation = useNavigation();
return (
<View>
<Button
onPress={() =>
navigation.navigate("ViewB", {
handleItem: (item) => console.log(item), // will log out "Your Item"
})
}
/>
</View>
);
};
const ViewB = ({ route }) => {
const navigation = useNavigation;
return (
<View>
<Button
onPress={() => {
route.params.handleItem("Your Item");
navigation.goBack();
}}
/>
</View>
);
};
If you are using react-navigation v2 you no need to use navigation.goBack() to go back to Main screen
this.props.navigation.navigate('Main', { myParam: value }) will declaratively handle the navigation back (with same transition) for you
Maybe you can save the data in the global state and call it again when you goBack
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
console.log("its focus");
//call the new data and update state here
});
return unsubscribe;
}, [navigation]);
Related
i have two button and they call same function like this:
this button created in useEffect.
useEffect(() => {
navigation.setParams({
TopRightButton: (
<ConfirmButton
callback={() => ApiCall()}
/>
),
});
}, []);
this is second button in render
<TouchableOpacity onPress={()=> ApiCall()}><Text>Add</Text></TouchableOpacity>
this is function:
const ApiCall = () => {
console.log('name', Name);
};
i change name with useState. when i click TouchableOpacity which is second button, it shows me name. However, when i click first button which is created in useEffect, nothing happen. i mean, Name is null. why this is happen ?
any advice ?
EDITED:
const [Name, setName] = useState('');
Will u try this way?
const ApiCall = () => {
console.log('name', Name);
};
useEffect(() => {
navigation.setParams({
TopRightButton: (
<ConfirmButton
callback={() => ApiCall()}
/>
),
});
}, [Name]);
You should provide more information concerning that first button, im guessing it is a button that you want to show on the right side of your stack navigator's header, if that's the case you should NOT use setParams for that.
If you want to configure your navigator you should use navigationOptions.
So in the screen where you want to add a button in its header, you have to call setOptions inside useEffect instead. Check out the docs for more info on how to achieve that.
I have a header in my app that needs to render a different button depending on whether or not the user has notifications. This is how I currently have it set up in my pages:
static navigationOptions = ({ navigation }) => {
return {
title: 'My Profile',
headerRight: () => (
<Button
type="clear"
icon={() => <Icon
type="material-community"
size={25}
name={UserProvider.bNotifications ? 'bell' : 'bell-outline'}
color={UserProvider.bNotifications ? COLORS.WARNING : COLORS.WHITE}
/>}
onPress={() => navigation.navigate('Notifications', null)}
/>
)
}
};
The problem is, if UserProvider.bNotifications changes value, the header button doesn't update unless the page is changed / rerendered.
I want to switch to use the navigation property that is passed into those navigationOptions, but I don't no how to access it from outside the navigation stack. UserProvider is a static class (NOT a component) so I can't access the navigation prop through the usual manner (or by using the useNavigation hook).
I do have a NavigationProvider class that has access to the NavigationContainer for the app. I use it to trigger navigation without components. Is there some way I can set the params on the navigation property using that same reference?
NavigationProvider:
import { NavigationActions } from 'react-navigation';
let _navigator;
function getNavigator() {
return _navigator;
}
function setTopLevelNavigator(navigatorRef) {
_navigator = navigatorRef;
}
function navigate(routeName, params) {
_navigator.dispatch(
NavigationActions.navigate({
routeName,
params,
})
);
}
function goBack() {
_navigator.dispatch(
NavigationActions.back()
);
}
export default {
navigate,
setTopLevelNavigator,
getNavigator,
goBack
};
The ref is set like this in my top level App component:
<AppContainer
ref={navigatorRef => {
console.log(navigatorRef.props.navigation);
NavigationProvider.setTopLevelNavigator(navigatorRef);
}}
/>
EDIT - UserProvider
This is just the gist of my UserProvider class, but should convey how it works.
export default class UserProvider {
private static _bNotifications: boolean;
static get bNotifications(): boolean {
if (!this.hasInitNotifications)
this.initNotficationWatch();
return this._bNotifications;
}
static set bNotifications(bNotifications: boolean) {
this._bNotifications = bNotifications;
}
static initNotficationWatch() {
//Firebase listener on notification
if(notifications){
this.bNotifications = true;
} else {
this.bNotifications = false;
}
}
}
How to set navigation params from outside navigation stack?
to do this you have to utilize the getParam method that comes from the navigation prop. the way I would di it would be to set a variable to a parameter that would equal to UserProvider.bNotifications.
static navigationOptions = ({ navigation }) => {
let notifications = navigation.getParam('notifications')
return {
title: 'My Profile',
headerRight: () => (
<Button
type="clear"
icon={() => <Icon
type="material-community"
size={25}
name={notifications ? 'bell' : 'bell-outline'}
color={notifications ? COLORS.WARNING : COLORS.WHITE}
/>}
onPress={() => navigation.navigate('Notifications', null)}
/>
)
}
};
you can set the param to an initial value by adding it as a second argument if needed navigation.getParam('paramName', 'param initial value')
To update the parameter you need to use the setParams method. For this you can use the useNavigation hook.
You can also do this inside of a functions instead of a element
// remember to const navigation = useNavigation()
<Button
title="Update param"
onPress={() => navigation.setParams({notifications: 'new value'})}
/>
you can also initiate the value this way... but I would recommend to initialize the value inside your navigationOptions
I haven't tested the code but it should work
RN DOCS: https://reactnavigation.org/docs/2.x/headers/
When I open the application and if the isAuth variable is true, it means the user has authorization, then I want to go to the provider screen.
My authorization component.
export const LoginScreen: NavigationStackScreenComponent<NavigationParams> = observer(({ navigation }: NavigationParams) => {
useEffect(() => {
AuthState.checkAuthentication();
}, []);
if (AuthState.isAuth) {
navigation.navigate('Provider');
}
return <View style={styles.body}>{LoaderState.loading ? <LoaderComponent /> : <AuthComponent />}</View>;
});
My provider component.
export const ProvidersScreen: NavigationStackScreenComponent<NavigationParams> = observer(({ navigation }: NavigationParams) => {
useEffect(() => {
ProvidersState.setProviders();
}, []);
return (
<View style={styles.body}>
{LoaderState.loading ? (
<LoaderComponent />
) : (
<ItemListComponent itemsList={ProvidersState.providersList} />
)}
</View>
);
});
But I get a warning. I understand that it is associated with the react-navigation library.
How to switch to another screen using a conditional statement?
Functional components are basically the equivalent to the render() function in class components. You are calling navigate before the component gets render and that's a problem.
You can either call the navigate inside your useEffect or put the conditional logic in the parent view.
In the first case, navigate will be called AFTER the component renders
useEffect(() => {
AuthState.checkAuthentication();
if (AuthState.isAuth) {
navigation.navigate('Provider');
}
}, []);
so it will be visible for half a second and then change. If you'd like to avoid this, then go for the second option.
You can put the condition in the parent. Something like
<View>{AuthState.isAuth ? <ProvidersScreen /> : <LoginScreen />}</View>
question regarding react navigation setParams(). I asked on Reactiflux, but no one responded. I'm trying to set a title programmatically in a function component.
From another Stack Overflow thread, updating the static title retroactively, like this, works:
const Comp = props => { ... };
Comp.navigationOptions = ({ navigation }) => ({
title: 'Static Title'
});
But I need to access the component state from within the component, this does not work:
const Comp =({ navigation }) => {
const [title, setTitle] = useState('');
useEffect(() => {
navigation.setParams({ title });
}, [title]);
return ( ... );
}
If setParams() is the wrong way to do it, please enlighten me
EDIT: To add to this, when I console.log(navigation) I can see that it is changing navigation.state.params.title to the correct string, however it doesn't show up as the title.
You need to get the title param and apply it to the title:
Comp.navigationOptions = ({ navigation }) => ({
title: navigation.getParam('title', /* your default title */)
});
First you need to implement your navigation option as a function and this function needs navigation parameter as shown example in following lines :
const cameraScreenNavigator = {
'/auth/controlledCameraScreen': {
screen: ControlledCameraScreen,
navigationOptions: ({navigation}) => ({
title: navigation?.getParam('title', "Başvuru Adı"),
headerStyle: style.navigationHeaderBlue,
headerTitleStyle: {
fontWeight: 'bold',
color: COLORS.primaryText
},
}),
}
}
Then you can call setParams function in your component. This function acting as setState but react-nativagion suggests this for
setParams "setParams/setOptions etc. should only be called in useEffect/useLayoutEffect/componentDidMount/componentDidUpdate etc. Not during render or in constructor."
props.navigation.setParams({title: "New Title"})
resource : https://reactnavigation.org/docs/stack-navigator/
I'm trying to pass params into a new screen, and implemented it like mentioned here.
I have the following TouchableOpacity button.
<TouchableOpacity
onPress={() => {
this.props.navigation.navigate('SomeScreen', {
title: 'Title',
subTitle: 'Subtitle',
});
}}
>
On the other page (let's call it Somescreen), I have the following:
render() {
const { navigation } = this.props;
const title = navigation.getParam('title');
}
But title above is undefined:
{ params: undefined, routeName: "Somescreen", key: "id-xx" }
My rootStack:
const RootStack = createStackNavigator({
SomescreenA: { screen: SomescreenA },
SomescreenB: { screen: SomescreenB },
}, { headerMode: 'none' });
Why are my params undefined in a new screen?
If you face a situation where your target screen get undefined params, probably you have a nested navigation stack.
Here you have to pass params to the navigate method in this way:
navigation.navigate('Root', {
screen: 'Settings',
params: { user: 'jane' },
});
For more information read this page in the official docs:
https://reactnavigation.org/docs/nesting-navigators/#navigating-to-a-screen-in-a-nested-navigator
In my specific case, I was calling a nested navigator, so I had to manage how send those params to their specific screen, so I did this:
Send params this way...the regular way:
navigation.navigate(
'OrderNavigator',
{itemSelected},
);
Then, from navigator stack I did this:
const OrderNavigator = ({route: {params}}) => {
return (
<Stack.Navigator initialRouteName="Order">
<Stack.Screen name="Order" component={Order} options={{headerShown: false}} initialParams={params} />
</Stack.Navigator>
);
};
And that's it. Then from the screen I got them like this:
const Order = ({route}) => {
const {itemSelected} = route.params;
const {first_name, last_name} = itemSelected;
return (...)
}
I've, unfortunately, encountered cases where navigate(route, params, ...) wouldn't pass the params object, just like you did.
As a workaround, I use the other variant - navigate({routeName, params, action, key}) that you can find here. It always works.
The accepted answer workaround did not work for me, so apparently if you use children to render your component (in screen options) and pass route as a prop, it works
if you are on react navigation v6^ use the useRoute hook to access the params object
const route = useRoute();
useRoute is a hook that gives access to the route object. It's useful when you cannot pass the route prop into the component directly, or don't want to pass it in case of a deeply nested child.
below is an implementation of this
import { useNavigation, useRoute } from '#react-navigation/native';
import { Pressable, Text } from 'react-native';
function Screen1() {
const navigation = useNavigation();
return (
<Pressable
onPress={() => {
navigation.navigate('Screen2', { caption: 'hey' });
}}
>
<Text> Go to Screen 2 </Text>
</Pressable>
);
}
function Screen2() {
const route = useRoute();
return <Text>{route.params.caption}</Text>;
}