How to pass a parameter in react native navigator? - reactjs

I tried an example of React Native Navigator:
const StudentStackNav = StackNavigator({
Home: {
screen: StudentLogin,
}
});
How do I pass a parameter to StudentStackNav and pass it to StudentLogin?
I have tried <StudentStackNav name='Lucy'> but this.props.name is not available in Home.

Normal props on a Navigator component can be used to configure the navigator.
To send arbitrary props to the screens, you have to use screenProps.
So for example:
<StudentStackNav screenProps={{ name: 'Lucy' }}/>
Which will be available in StudentLogin as this.props.screenProps.
screenProps is documented on this page

Related

What is the equalent for navigationOptions in React Navigation V6.0?

In V4.0 we could configure any screen inside it using navigationOptions.
for example.
In HomeScreen component we could configure it using
HomeScreen.navigationOptions = { ...config }
what is the equalent in V6.0?
in v6 if you want to add navigation option you can use the simple option like this
HomeScreen:{
screen:HomeScreen,
navigationOption:{...config}
}

Access custom component props and URL parameters from react-router-dom in TypeScript

I have a route in react-router-dom set up like this:
<Route path="/result/:result" component={ResultsView} audio={audio} speechRecognition={speechRecognition} />
And a component with typed props like this:
interface ResultsViewProps {
audio: HTMLAudioElement;
speechRecognition: Types.SpeechRecognition;
}
interface ResultsViewRouterParams {
result: string;
}
interface ResultsViewState {
...
}
export default class ResultsView extends React.Component<
ResultsViewProps & RouteComponentProps<ResultsViewRouterParams>,
ResultsViewState
> {
...
}
As you can see, I'm getting a :result parameter from the URL, which I want to pass to ResultsView. At the same time, I also want to pass the custom props audio and speechRecognition to the same component. Unfortunately, I'm stuck here. I've just recently migrated this project to TypeScript (from pure JS). Previously the above way worked, now TypeScript obviously complains that "Route" doesn't have those custom props. I've tried several ways to instead of simply passing "ResultsView" as the component to the Route, to pass a component with the custom props included, etc., but all those ways didn't work either.
How would I go about doing that?
Found a solution. When using react-router-dom v5, it's possible to use the render property instead of component to pass in the props for the child component. In my case, this looks like the following:
<Route
path="/result/:result"
render={(props) => <ResultsView audio={audio} speechRecognition={speechRecognition} {...props} />}
/>
I also simplified the typing of the components props like so:
interface ResultsViewProps extends RouteComponentProps<ResultsViewRouterParams> {
audio: HTMLAudioElement;
speechRecognition: Types.SpeechRecognition;
}
interface ResultsViewRouterParams {
result: string;
}
interface ResultsViewState {
...
}
export default class ResultsView extends React.Component<ResultsViewProps, ResultsViewState> {
...
}
Inside the component, it's then possible to read the param through this.props.match.params.result.

Is there a way to pass state to pages in Gatsby?

Since Gatsby effectively hides the router, you can't pass props to each page in the way you would with BrowserRouter in Create-React-App. Is there a way to do this in Gatsby? I assume I need to do it somehow in Gatsby-browser.js. I basically want to maintain a state called Step, that is accessible by all pages. Would I have to use Context for this?
You can pass state into a page with Link (docs), but be mindful of pages being built without state (i.e. statically).
<Link
to={`/photos/`}
state={{ tag }}
>
See more {tag}
</Link>
const PhotosPage = ({ location: { state } }) =>
<div>{state?.tag ? `${tag} photos` : "All photos"}</div>
The native (and easiest) way is using React context but you have multiple ways of sharing a global state in Gatsby:
Using global wrappers within the wrapRootElement exposed API:
import React from "react"
import { ThemeProvider } from "./src/context/ThemeContext"
export const wrapRootElement = ({ element }) => (
<ThemeProvider>{element}</ThemeProvider>
)
If you follow this approach, you'll need to use wrapRootElement in both gatsby-browser.js as well gatsby-ssr.js since it's a shared API.
Keep in mind that Gatsby's router extends from #reach/router (from React).
In that way, you'll keep your step state across the application.

react-navigation Screen that conceals TabBar from nested StackNavigator

I'm new to react-navigation and trying to wrap my head around how to do the following:
Given this navigation structure:
RootTabNavigator
LoggedOut_StackNavigator
...
LoggedIn_StackNavigator
LoggedIn_TabNavigator <-- TabBar rendered by this Navigator
TabA_StackNavigator
ScreenA
ScreenB
I would like to be able to navigate from ScreenA to ScreenB using the typical "slide in from right" transition, in such a way that the TabBar is visible on ScreenA, but is not visible on ScreenB. In other words, when I navigate to ScreenB, I want it to take up the entire window.
Once the user transitions from ScreenA to ScreenB, they can either press the back button to return back to ScreenA, or navigate to new routes using the same transition with the TabBar still not visible.
What I've tried:
navigationOptions.tabBarVisible: this property only seems to work when applied to TabA_StackNavigator itself, which means that all of the screens in its stack also conceal the TabBar. Adding it to the screens inside the StackNavigator has no effect.
Adding a new AllScreens_StackNavigator as a sibling of LoggedIn_TabNavigator and navigating to routes inside this navigator, I get the error: Expect nav state to have routes and index, {"routeName":"ScreenB", "params": {}, "key": "init-id-1516..."}. The navigation action I dispatched to try to do this:
{
"action": Object {
"params": Object {},
"routeName": "ScreenB",
"type": "Navigation/NAVIGATE",
},
"params": Object {},
"routeName": "AllScreens_StackNavigator",
"type": "Navigation/NAVIGATE",
}
Any help is greatly appreciated!
Edit: this answer is relevant to react-nagivation v1.~ (pre v2.0)
As suggested in the comments, see this issue:
https://github.com/react-navigation/react-navigation-tabs/issues/19
Apparently, the navigationOptions of an inner component affect the containing navigator's parent navigator as well.
Solution
That means this code should work for you:
class ScreenB extends React.Component {
static navigationOptions = {
header: () => null, //this will hide the Stack navigator's header (TabA_StackNavigator)
tabBarVisible: false //this will hide the TabBar navigator's header (LoggedIn_TabNavigator)
}
Explanation
First, you can set the navigation options per individual screen (component). You can see how in the code snippet above or here: React Navigation - Screen Navigation Options
Second, you tried:
Adding it to the screens inside the StackNavigator has no effect.
It didn't work because hiding the StackNavigator's header requires setting the header field to null.
From the React Navigation documentation:
React Element or a function that given HeaderProps returns a React
Element, to display as a header. Setting to null hides header
Third, using tabBarVisible is actually correct, but it affects only the TabNavigator. And to make it disappear only for one tab and not for all the tabs, you need to set it on the specific screen. ScreenB in your case.
Hope this helps!
The following is what ended up working for me, so I'm posting it the hopes that it helps others. I haven't had a chance to try #talzaj's implementation so I'll leave it up to others to upvote whatever works best for them. The following solution has been working well for me, including inside nested navigators.
I updated my navigation structure such that:
LoggedIn_StackNavigator still has LoggedIn_TabNavigator as one of its screens, and this LoggedIn_TabNavigator is the initial route of LoggedIn_StackNavigator as set using initialRouteName.
LoggedIn_StackNavigator also contains a route for every screen that will ever need to be shown full screen and conceal the tab bar. (If you are re-using screens, where some are shown with the tab bar visible and others where it is not, make sure to use unique keys for routes that re-use the same screen.
Navigation Structure
So, the navigation structure looks like:
RootTabNavigator
LoggedOut_StackNavigator
LoggedIn_StackNavigator
ScreenA // ( reuse screen component, different route key )
ScreenB // ( reuse screen component, different route key )
LoggedIn_TabNavigator <-- TabBar rendered by this Navigator
TabA_StackNavigator
ScreenA
ScreenB
LoggedIn_StackNavigator:
And LoggedIn_StackNavigator looks like:
import { StackNavigator } from 'react-navigation';
import LoggedIn_TabNavigator from './LoggedIn_TabNavigator';
import {
ScreenA,
ScreenB,
} from './LoggedIn_TabNavigator/TabA_StackNavigator/Screens';
const LoggedIn_StackNavigator = StackNavigator({
WithoutTabBar_ScreenA: {
screen: ScreenA
},
WithoutTabBar_ScreenB: {
screen: ScreenB
},
LoggedIn_TabNavigator: {
screen: LoggedIn_TabNavigator
}
}, {
initialRouteName: 'LoggedIn_TabNavigator'
});
export default LoggedIn_StackNavigator;
From there, I wrote a helper HOC for pushing full screen routes:
import React from 'react';
import { withNavigation } from 'react-navigation';
import { fullScreenRoutePrefix } from './somewhere';
export default function withNavigateFullScreen(Child) {
#withNavigation
class WithNavigateFullScreenHOC extends React.Component {
navigateToFullScreenRoute = (routeName, params) => {
this.props.navigation.navigate(
`${fullScreenRoutePrefix}${routeName}`, params
);
}
render() {
return (
<Child
{...this.props}
navigateFullScreen={this.navigateToFullScreenRoute}
/>
);
}
}
return WithNavigateFullScreenHOC;
}
And then I can navigate to full screen routes like so:
import React from 'react';
import { withNavigateFullScreen } from 'components/higher-order';
import { Text } from 'react-native';
#withNavigateFullScreen
export default class ScreenA extends React.Component {
goToScreenB = () => {
this.props.navigateFullScreen('ScreenB');
}
render() {
return <Text onPress={this.goToScreenB}>Go To Screen B</Text>;
}
}

React Navigation trigger when routeName changed

I'm using react navigation for navigate screen. I used nested navigation, TabNavigator and StackNavigator. How can I know in current screen has been swipe / change to other screen and change the state inside the screen without using Redux . I try to get this.props.navigation.state.routeName , it get the routeName of the screen, but how to trigger when routeName has change
const mainNav = TabNavigator({
Home: {
screen: HomeScreen,
},
Live: {
screen: LiveScreen,
},
Radio: {
screen: RadioScreen,
},
} );
export const mainStack = StackNavigator({
Home: { screen: mainNav},
Content: { screen: ContentScreen },
});
At present there is no way to track swipe gestures in react navigation. You can use hacks to achieve this, But mostly all of them requires hooking react navigation with redux.
Best way to track your screens will be to use react redux and hook the state with appState. This will give you most control over navigation and you can also use redux actions to control navigations along with other business stuff f in the app.
Simplest method to use react navigation with redux
You can refer
https://github.com/react-community/react-navigation/issues/1063

Resources