React Native StackNavigator initialRouteName with parameters - reactjs

In 'react-navigation' library, How can I send the parameters with initialRouteName in Stack.Navigator.
return (
<Stack.Navigator
initialRouteName={routeName}
screenOptions={{
animation: 'slide_from_right',
}}>
This is the return of my navigation file and I'm setting the routeName dynamically but the screen on which I want to initially route must need route parameters to pass.

you can utilize the prop "initialParams" that can be added to your screen component
<Screen
initialParams={{id:0}}
{...otherScreenProps}
/>
you can also handle it with a condition like initialParams={initialRouteName === screenName ? {id:0} : undefined}
I believe there are other options like setParams, but i'm unsure of your exact use case

you can pass params as below.
initialParams={{ itemId: 42 }}
These initialParams props are provided by react-navigation, you can use that initially.
also whenever you setparams from the specific screen you can use the code below.
navigation.setParams({
itemId: {set your dynamic value},
});
for the reference :-
click here

Related

Equivalent of dynamic query params for React Native Navigation?

I want to dynamically show profiles based on userId in React Native. In react where I set up my routes, I'd add something like route="/users/:userId", and then use that userId to make various calls, display various data, etc. When I implement a link to the profile page, I route them to, say, /users/1.
How can I achieve something similar in React Native? The only thing seen around the web is to pass it in as params, but does that mean I've got to pass it in each time I call navigation.navigate? I'm not sure what the route-defining or the navigation.navigate syntax should look like.
I've checked a couple of SO threads, but none of them seem to answer this fundamental question. And all of the docs and articles about dynamic routing in React Navigation seem to mostly concern passing in dynamic title headers and stuff.
React Navigation primarily uses a params object which looks like { userId: 1 } rather than a string-based route definition like "/users/:userId".
Linking to a Profile
The navigation.navigate function takes two props: the name of the route and the params to pass. You don't need to include the second params argument at all if you are navigating to a route which doesn't take any parameters. navigation.navigate("Home") is fine. But when going to your "User" route you will always need to include a userId.
In order to go to a particular user profile, you would call:
onPress={() => navigation.navigate("User", { userId: 1 })}
Docs: Passing parameters to routes
Accessing Params
That userId param can then be accessed in the UserScreen component through the props which are injected by the navigator. Every screen receives props route and navigate. The params are a property of the route prop.
So you can define a UserRoute component like this, where we get the current userId from route.params.userId.
const UserScreen = ({route, navigation}) => (
<View>
<Text>Viewing profile for user #{route.params.userId}</Text>
<TouchableOpacity onPress={() => navigation.navigate("Home")}>
<Text>Back to Home</Text>
</TouchableOpacity>
</View>
);
(Typescript users: this component is React.FC<StackScreenProps<RootStackParamList, "User">> where RootStackParamList is your own app's param definitions)
Declaring Routes
You don't actually need to say anything about the params when you create your routing. This works just fine:
export const App = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="User" component={UserScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
There are some additional optional configurations that you can use. You can map the params to options or map the params to a unique screen id, for example.
<Stack.Screen
name="User"
component={UserScreen}
options={({ route }) => ({
title: `User Profile #${route.params.userId}`
})}
getId={({ params }) => params.userId.toString()}
/>
(Typescript users will want to define a type, typically called RootStackParamList, which maps each route to its params types. This is then used as the generic on StackScreenProps, StackNavigationProp, etc.)
String-Based Navigation
React Navigation does support linking to paths like "/user/1", but it requires additional configuration. Behind the scenes it still uses a params object, so you need to define a mapping from the path to the params. It can be a custom mapping, or you can use the same syntax that React Router does with : to define params. "users/:userId" will create a params object with the userId as the key.
Your Stack.Screen component stay the same. The configuration options are passed as a prop linking to the NavigationContainer component. If you set this up then you are able to use the experimental Link component like you would in React Router to link to a path like "/users/1".
export const App = () => {
return (
<NavigationContainer
linking={{
prefixes: ["https://yourdomain.com"],
config: {
screens: {
Home: "",
User: "users/:userId"
}
}
}}
>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="User" component={UserScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
CodeSandbox Demo with typescript types.

How to find current screen/route in nested Tab.Navigator

I have a custom TabBar for a Tab.Navigator that needs to have a different action when one of the tabs is selected based on what the current route is in the Stack Navigator component for that tab.
How can I inspect the currently displayed Stack.Screen inside of this custom TabBar? Trying to use the getRoute hook only shows me the parent screen that hosts that Tab.Navigator.
<Tab.Navigator tabBar={(props) => <BottomTabBar {...props} />}>
<Tab.Screen
name="Home"
component={HomeStack}
initialParams={{showSuccess: route.params?.showSuccess}}
/>
<Tab.Screen name="Alternate" component={AlternateScreen} />
</Tab.Navigator>
I can't pass the value in using tabBarOptions as I don't know what the selected route would be when the tab bar is created.
I ended up keeping track of the current screen outside the scope of the navigator as the built in Tab Navigator did not keep a reference to nested screens in a Stack Navigator like I was hoping it would.
Only needing to determine a difference between two screens, my crude hack was to have a current screen reference in a context hook and update that value in a useEffect hook when the relevant screen was mounted.
In whatever your provider is, have a currentScreen const like this:
const currentScreen = useRef('Closet');
Then, in your screens, destructure that value from the provider in the useContext hook:
const { currentScreen } = useContext(MyContext);
Then, in the same screen update that currentScreen value in a useEffect hook:
useEffect(() => {
currentScreen.current = 'NewScreen';
}, []);

How to set a loading state for react component while sorting and filtering data?

I am trying to implement a table and do filtering and searching of data from the table. Since the searching and sorting takes a while I would like to implement a spinner display to show that the search/filtering is running.
Below is how I have implemented the component, I call filterData/ searchData to search through the data and return the results which is passed as props to the Grid Table component and where the data is displayed.
{this.state.search && this.state.filter &&
<GridTable
results= {filterData(this.state.filter,searchData(this.state.search,this.state.Data))}
/>}
{ this.state.search && !this.state.filter &&
<GridTable
results = {searchData(this.state.search,this.state.Data)}
/>}
{ !this.state.search && this.state.filter &&
<GridTable
results= {filterData(this.state.filter,this.state.Data)}
/>}
{ !this.state.search && !this.state.filter &&
<GridTable
results = {this.state.Data}
/>}
Where should i implement a loading state and set its state? I am confused since I am directly passing the result of the search/ filter functions into the props.
In your render method you can have one loader implemented like
<Loader visible={this.state.visibility}>
In your searchData method, you can set the visibility of this loader true in the first line and false in the last line like below
searchData = () => {
// Start the loader
this.setState({
visibility: true,
});
// ....Your logic goes here
// Stop the loader
this.setState({
visibility: false,
});
};
I suppose that loading state relates to the whole Grid component. It is sound wisely if you manage this state in root of your module (Table/Grid).
To pass global module state, like loading state, to children components you may use React Context API or some external state management library (Redux/Effector etc.).
After that you can easily use conditional rendering to show spinner while data is loading.
The Ideal way to handle this scenario is when you are triggering the search/sort function.
//Initial State:
this.state= {
isLoader: false
}
filterData( some arguments){
this.setState({ isLoader: !this.state.isLoader})
// Do your API Call or filter logic here, once you receive your response
this.setState({ isLoader: !this.state.isLoader})
}
Inside your render function, toggle your Loader based on the state changes.
render() {
return (
this.state.isLoader ?(<Loading />) : <YourComponent/>
)}

React native navigate to ID of specific post

I would like to navigate the same way you do with react-router.
I am fetching an API and display the results as cards, when you click a card, I need it to navigate to a specific ID based on the card selected.
<Route path='/item:id' component={item-details} />
and then on the card, you do this.<Link to='item/:id' > Card...</Link>
That's how you do it with react-router-dom...I need to archive the same with React Native.
Any solutions?
I suggest using react-navigation, it's the best solution for navigation for a RN app. It's not quite like React Router but RN requires a different method. In react-navigation, you declare your screens as 'navigators', e.g stack navigator.
import { createStackNavigator } from '#react-navigation/stack';
const Stack = createStackNavigator();
function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Screen1" component={Screen1Component} />
<Stack.Screen name="Screen2" component={Screen2Component} />
</Stack.Navigator>
);
}
On each screen, a navigation prop is passed down. This has a lot of properties and functions but one is a function called navigate, which takes you to another screen in your stack. For example:
const Screen1Component = ({ navigation }) => (
<View>
// content
<TouchableOpacity onPress={() => navigation.navigate('Screen2) })>Go to Screen2</TouchableOpacity>
</View>
)
navigate also has a second parameter it can take called screen params. These are parameters you can pass between screens when you navigate. It's used like navigation.navigate('Screen2, { id: '1234' }).
In your Screen2 component, there will be a route prop, where you can then pick that param up and use it, for example:
const Screen2Component = ({ route, navigation }) => {
const { id } = route.params
// do something with it, call api, pass to redux action,etc
return ...
}
Hope that helps.

React Navigation: Set header color before render

I'm creating an app where the user can change the theme, I'm using react navigation's header and I know I can update navigationOptions by calling setParams() but calling it on useEffect() is too late, it renders the default color of the header before rendering the correct color.
I'm using functional state components by the way.
useEffect(() => {
navigation.setParams({
backgroundColor: (theme === THEME_STANDARD) ? 'white' : Colors.appNight
});
}, [theme]);
Above is the code I use at the moment, it updates the header color automatically when I click the button for change theme, but when I navigate to this Screen, it shows the default color before showing the correct theme color. Do you guys have any idea on how to accomplish this? Thank you for any help!
useLayoutEffect is probably what you are looking for, this runs code before the browser paints to the screen.
useLayoutEffect(() => {
navigation.setParams({
backgroundColor: theme === THEME_STANDARD ? 'white' : Colors.appNight
});
}, [theme]); // or empty dependency array if you only want it to run when the component mounts

Resources