Initial route params in React Navigation v5? - react-native

React Navigation v3 was featuring an initialRouteParams property to pass initial values to this.navigation.props. Is there a way to set initial route params to be accessed via route.params in the React Navigation v5?
function MainScreen({route, navigation}) {
return (
// how to pass default values to route in here?
// route.params.userParam ?
...
);
}

It could be accomplished by passing initialParams to the Stack.Screen:
<Stack.Screen
name="Main"
component={MainScreen}
initialParams={{ /* initialParams */ }}
/>
There is also a handy default syntax one can use (see No more getParam):
route.params?.userParam ?? 'defaultValue'

Related

React Navigation how to setup children routes

I have a React Native Expo application using React Navigation. I think I have all the navigation routes (links) not well setted up.
So in my app let's say I have a Profile screen which has 2 list items to navigate. Application settings & User settings. These two have some more items inside each one.
My navigation tree would be something like:
ProfileScreen (screen with 2 items => User settings | Application settings)
UserSettings:
Language (Navigation to LanguageScreen)
Change password (Navigation to ChangePasswordScreen)
Personal data (Navigation to PersonalDataScreen)
ApplicationSettings:
...
My LinkingConfiguration is configured like:
profileStack = {
initialRouteName: "profile",
screens: {
profile: "profile",
userSettings: "profile/userSettings",
language: "profile/userSettings/language",
changePassword: "profile/userSettings/password",
personalData: "profile/userSettings/personalData",
applicationSettings: "profile/applicationSettings"
}
}
profileStack is a navigation stack. The rest are screens.
I'm wondering how I need to setup well the tree, because if I deep link to myApp.com/profile/userSettings/language, if I go back, I go directly to the initialRouteName which is profile, and I guess this is because the tree is not well generated.
In angular router would be setted as
profile: path: "...", children: [ userSettings: path: "...", children: [ {...}]]
How does navigation tree have to be setted up correctly in my example? Maybe using many navigation stacks?
Can anybody enlight me?
FYI:
React Navigation: v6 (it was also happenning in v5)
React Native: v0.69.5
Expo: v46.0.9
React Navigation allows you to set up the same hierarchy you showed in your example. You want to nest the navigators just as in your depiction.
https://reactnavigation.org/docs/nesting-navigators
Something like:
function Profile() {
return (
<Stack.Navigator>
<Stack.Screen name="UserSettings" component={UserSettings} />
<Stack.Screen name="ApplicationSettings" component={ApplicationSettings} />
</Stack.Navigator>
);
}
function UserSettings() {
return (
<Stack.Navigator>
<Stack.Screen name="Language" component={Language} />
<Stack.Screen name="ChangePassword" component={ChangePassword} />
<Stack.Screen name="PersonalData" component={PersonalData} />
</Stack.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<Profile />
</NavigationContainer>
);
}
The structure of navigation is created by how you nest components.

React Native: How to handle protected routes with react navigation

What I want is to protect specific screens where the user can run specific actions and only at that point redirect him to a login screen, if the user is successfully authenticated, redirect him to the point where he left off the flow.
We can do this in React JS(with react-router), so I would like to know if its posible to implement a similar solution for react-native(with react-navigation):
React JS approach with React Router
function RequireAuth({ children }) {
const { authed } = useAuth();
const location = useLocation();
return authed === true ? (
children
) : (
<Navigate to="/login" replace state={{ path: location.pathname }} />
);
}
This is possible in react native and is documented in the authentication workflow section of the documentation.
In summary we conditionally need to render screens inside the navigator. Here is a minimal example using a Stack.Navigator which is similar to your posted code snippet. The workflow is identical for other navigators (nested or not). I will use the context api in my example, but there are other ways to achieve the same as well. The overall pattern is the same.
const AppContext = React.createContext()
function App() {
const [isSignedIn, setIsSignedIn] = React.useState(false)
const appContextValue = useMemo(
() => ({
isSignedIn,
setIsSignedIn,
}),
[isSignedIn]
)
return (
<AppContext.Provider value={appContextValue}>
<Stack.Navigator>
{!isSignedIn ? (
<Stack.Screen
name="Login"
component={LoginScreen}
/>
) : (
// whatever screens if user is logged in
<Stack.Screen name="Home" component={HomeScreen} />
)}
</Stack.Navigator>
</AppContext.Provider>
);
In the LoginScreen, you then need to change the authed state to true if the login was successful. The first screen in the conditional will then be initially rendered automatically (in this case HomeScreen).
function LoginScreen() {
const { setIsSignedIn } = useContext(AppContext)
// do whatever, then setIsSignedIn to true
}

Expo v4 / React : Passing datas between tab screen

Expo v4..
Hello friends,
I am using expo tab navigation:
https://reactnavigation.org/docs/hello-react-navigation
How can I pass datas bewteen expo tabs ?
OrderScreen.tsx:
import { createMaterialTopTabNavigator } from '#react-navigation/material-top-tabs';
const Tab = createMaterialTopTabNavigator();
export default function OrderScreen({navigation, route}) {
let data = route.params
return (
<Tab.Navigator>
<Tab.Screen name="Details" component={DetailsScreen} />
<Tab.Screen name="Photos" component={PhotosScreen} />
</Tab.Navigator>
);
}
PhotosScreen.tsx:
export default function PhotosScreen() {
// HOW TO GET route.params here ??
DetailScreen.tsx:
export default function DetailsScreen() {
// HOW TO GET route.params here ??
I manage to have data in only one tab using :
navigation.navigate('Order', {screen: 'Details' ,params: {datas:someDatas}});
But I want to have the datas in both tabs.
I have been searching everywhere but impossible to find.
I would be very surprise there is no solution for that.
T H A N K S !!!! :-)
finding no answer on the net, I've been using the context api.
for a guy new to react it took a while to get the idea of context but it seems to be quite powerful once settled.

React Navigation passing function as parameter

so i have lot of screen that have similar function eg:
ForgotPasswordCaptcha
ForgotUserIDCaptcha
RegisterCaptcha
these screens have same layout and functionality except they have different "Next" Button function in ForgotPassword users will be redirected into loginscreen, in ForgotUserID the user will be redirected into page that shows his userID. and in Register it will redirect user to Succes Page.
.
so the function that i create in navigator is handleOkay, and when i press the button in SomeReusableScreen it gives me this warning
Non-serializable values were found in the navigation state. Check:
forgotUserIDStackScreen > FUinputCASAScreen > params.handleOkay (Function)
This can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params.
what i want to achieve is i to pass function as parameter in Stack navigator so the screen will just invoke that function to redirect/doing something with redux,
i dont know i should ignore this warning since in other screens it will handle redux sagas, set asyncstorage
so i have found the way to do what i wanted.
instead of passing the screen as component in Stack.Screen i pass it as child like this
<Stack.Screen
initialParams={{progress: 0.2}}
name={routes.nameofthisroute}
options={({navigation, route}) => ({
headerTitle: props => {
let currentProps = {navigation, route};
return <NavigationHeaderTwo {...currentProps} />;
},
...otherStyle,
})}>
{props => (
<PickMethodScreen handlePickMethod={handlePickMethod} {...props} />
)}
</Stack.Screen>
and i props some function and state from Stack Navigator and its written in this docs here
we can also create react context so component can consume it without having lot of props
I implemented a very simple example to clear the concept. You can pass function as a prop and can dispatch up to the parent component using the same props key. This way you can utilize reusable component.
//consider this your generic Component
function IButton(props){
//receive the method as props
//dispatch the method back to the parent
return (
<button onClick={()=>props.handleClick('hello')}>click me </button>
)
}
const App=()=>{
function handleOnClick(text){
alert(text);
}
return(
<div>
{/*pass the function as Prop*/}
<IButton handleClick={handleOnClick}/>
</div>
)
}
ReactDOM.render( < App / > , document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

React Navigation Custom Header and Custom Back Button

I am using React Navigation. I created a custom header component myself. I call this component into other components. But the back button I use on the header doesn't work for other components. How can I add this to the react navigation stack.
navigation.back() or navigation.navigate('Home)
I get an error when I write.
Maybe you not transmit navigation? print console.log(navigation). And you can use navigation.goBack()
You can use this: function LeftMenu(props) { return ( <Drawer.Navigator initialRouteName={props.route} drawerContent={(props) => <Custom_Side_Menu {...props}/>} drawerContentOptions={{activeTintColor: 'rgb(219,218, 218)'}}> <Drawer.Screen name="Map" component={MapScreen}/> </Drawer.Navigator> ); }
And you can get navigation in props LeftMenu