React Router renders two components on the same page - reactjs

I've looked at the other questions similar to this, and none of them seem to solve this.
I want to use react router to link to another page.
This is the return of my component:
<NativeRouter>
<View style={styles.container}>
<TextInput
onChangeText={value => this.onChangeText('username', value)}
style={styles.input}
placeholder='username'
/>
<TextInput
onChangeText={value => this.onChangeText('password', value)}
style={styles.input}
secureTextEntry={true}
placeholder='password'
/>
<Button style={styles.button} title="Sign In" onPress={this.signIn.bind(this)} />
<TextInput
onChangeText={value => this.onChangeText('confirmationCode', value)}
style={styles.input}
placeholder='Confirmation Code'
/>
<Button style={styles.button} title="Confirm Sign In" onPress={this.confirmSignIn.bind(this)} />
<Link to='/forgotPassword'>
<Text>Forgot Password</Text>
</Link>
<Switch>
<Route path='/forgotPassword' component={ForgotPassword} />
</Switch>
</View>
</NativeRouter>
Whenever I click on the link, the link renders the ForgotPassword component on the same page.
Ideas?
This is inside my app.js.
<Switch>
<Route path="/signin" component={SignIn} />
<Route path="/forgotPassword" component={ForgotPassword} />
</Switch>
</View>

the Route inside your component will get replaced with ForgoPassword component when the url matches, You should define the routes in the parent component
Example
import React from "react";
import { StyleSheet, Text, View, AppRegistry } from "react-native";
import { NativeRouter, Route, Link } from "react-router-native";
const Home = () => <Text style={styles.header}>Home</Text>;
const SignIn = () => <Text style={styles.header}>SignIn</Text>;
const ForgotPassword = () => <Text style={styles.header}>ForgotPassword</Text>;
const App = () => (
<NativeRouter>
<View style={styles.container}>
<View style={styles.nav}>
<Link to="/" underlayColor="#f0f4f7" style={styles.navItem}>
<Text>Home</Text>
</Link>
<Link to="/signIn" underlayColor="#f0f4f7" style={styles.navItem}>
<Text>Sign In</Text>
</Link>
<Link
to="/forgotPassword"
underlayColor="#f0f4f7"
style={styles.navItem}
>
<Text>Forgot Password</Text>
</Link>
</View>
<Route exact path="/" component={Home} />
<Route path="/signIn" component={SignIn} />
<Route path="/forgotPassword" component={ForgotPassword} />
</View>
</NativeRouter>
);
const styles = StyleSheet.create({
container: {
marginTop: 25,
padding: 10
},
header: {
fontSize: 20
},
nav: {
flexDirection: "row",
justifyContent: "space-around"
},
navItem: {
flex: 1,
alignItems: "center",
padding: 10
},
subNavItem: {
padding: 5
},
topic: {
textAlign: "center",
fontSize: 15
}
});
AppRegistry.registerComponent("MyApp", () => App);
sandbox

Related

goBack not working in nested navigators react native. TabNavigator and StackNavigator

I have this problem several days ago and I can't find a solution.
This is my navigation structure
Index.tsx -->
<NavigationContainer>
<Stack.Navigator initialRouteName='tabsBottomHome'
screenOptions={{
headerTitle: () => <Header />,
headerBackground: () => <HeaderBackground />,
headerLeft: ({ onPress, canGoBack }) =>
canGoBack ? (
<Pressable onPress={onPress} style={{ width: 30, height: 15 }}>
<ArrowLeft height={15} width={15} style={{ marginLeft: 15 }} />
</Pressable>
) : (
<Pressable style={{ width: 65, height: 35 }}></Pressable>
),
headerRight: () => <HeaderRight />,
}}
>
{state.isSignIn ? (
<>
<Stack.Screen
name='tabsBottomHome'
component={TabsBottomHome}
options={{headerShown: false }}
/>
</>
) : (
<>
<Stack.Screen
name="Login"
component={LoginScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="LoginError"
component={LoginError}
/>
</>
)}
</Stack.Navigator>
</NavigationContainer>
This would be the first navigation of my application. So far everything is going well.
TabsBottomNavigation -->
<Tab.Navigator
initialRouteName='Home'
screenOptions={{
headerShown:true,
tabBarShowLabel:false,
tabBarStyle:style.tabsBottomContainer,
unmountOnBlur: true,
headerTitle: () => <Header />,
headerBackground: () => <HeaderBackground />,
headerLeft: () =>
routeName != "Home" ? (
<Pressable onPress={navigateBack} style={{ width: 65, height: 15 }}>
<ArrowLeft height={15} width={15} style={{ marginLeft: 15 }} />
</Pressable>
)
: (
<Pressable style={{ width: 65, height: 35 }}></Pressable>
)
,
headerRight: () => <HeaderRight />,
}}
sceneContainerStyle={style.backgroundContent}
screenListeners={({route})=>({
state: ()=> {
setRouteName(route.name);
}
})}
backBehavior={'history'}
>
<Tab.Screen
name='Assets'
component={AssetScreen}
options={{tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconAsset}
style={{
tintColor: focused ? '#00B2DF' : '',
marginTop: 8
}}
/>
</View>
)}} />
<Tab.Screen
name='GatewayStack'
component={ConnectGatewayStack}
options={{tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconBluetooth}
style={{
tintColor: focused ? '#00B2DF' : ''
}}
/>
</View>
)}} />
<Tab.Screen
name='Home'
component={HomeScreen}
options={{tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconHome}
style={{
tintColor: focused ? '#00B2DF' : ''
}}
/>
</View>
)
}} />
</Tab.Navigator>
everything is fine here too, the conflict is in the ConnectGatewayStack stack
ConnectGatewayStack -->
export type StackConnectList = {
Connect: undefined;
QRScan: undefined;
GatewayList: undefined;
GatewayInfo: undefined;
NotFoundGateway: undefined;
GatewayDetected: undefined;
ErrorConnecting: undefined;
}
const GatewayStack = createStackNavigator<StackConnectList>();
const ConnectGatewayStack = () =>{
return (
<GatewayStack.Navigator initialRouteName='Connect'
screenOptions={{headerShown:false}}
>
<GatewayStack.Screen name='Connect' component={ConnectScreen} />
<GatewayStack.Screen name='GatewayList' component={GatewayList} />
<GatewayStack.Screen name='GatewayInfo' component={GatewayInfo} />
<GatewayStack.Screen name='QRScan' component={QRScanScreen} />
<GatewayStack.Screen name='NotFoundGateway' component={NotFoundGateway} />
<GatewayStack.Screen name='GatewayDetected' component={GatewayDetected} />
<GatewayStack.Screen name='ErrorConnecting' component={ErrorConnecting} />
</GatewayStack.Navigator>
)
}
export {ConnectGatewayStack};
When I navigate to the ConnectGatewayStack tab, which contains the other components that I just showed, if I go to a child component and press the back button in header, it returns directly to the TabsBottomHome (that is, to the Tabs navigation) and not to the component that was previously visited.
For the navigation back, i use
import { useNavigation } from '#react-navigation/core';
whit
const navigation = useNavigation();
navigation.goback();
I tried whit diferents methods, but none solved my problem.
example test whit
backBehavior={'history'}
backBehavior={'order'}
and many functions of the core react-native and react-native-navigation
any ideas?
sorry for my bad english and thank you very much

Why is react-three-drei's OrbitControls breaking when I use View with Routes?

I am loading multiple 3D elements in my pages, so to avoid creating multiple canvases I use react-three-drei's View.
My <Canvas> is inside App.js and outside of my react-router-dom's <Routes>.
The problem is upon changing route the <OrbitControls> appear to break as I cannot move the object around with the mouse anymore.
App.js
export default function App() {
const [canvasWrapperRef, canvasView1, canvasView2] = useRefs();
const canvasRefs = { canvasView1, canvasView2 };
return (
<div className="App">
<div ref={canvasWrapperRef}>
<Suspense fallback={null}>
<Routes>
<Route path="/" element={<Homepage ref={canvasRefs} />} />
<Route path="/other" element={<OtherPage ref={canvasRefs} />} />
</Routes>
<Canvas
onCreated={(state) => {
console.log("canvas created");
state.events.connect(canvasWrapperRef.current);
}}
className="canvas"
>
<View track={canvasView1}>
<Scene />
<TransformControls>
<Soda scale={6} position={[0, -1.6, 0]} />
</TransformControls>
<OrbitControls makeDefault />
</View>
<View track={canvasView2}>
<color attach="background" args={["lightblue"]} />
<Scene />
<TransformControls position={[0, -1, 0]}>
<Duck scale={2} position={[0, -1.6, 0]} />
</TransformControls>
<OrbitControls makeDefault />
</View>
<Preload all />
</Canvas>
</Suspense>
</div>
</div>
);
}
function Scene() {
return (
<>
<ambientLight intensity={1} />
<Environment preset="dawn" />
</>
);
}
Homepage.js
const Homepage = React.forwardRef((props, ref) => {
const { canvasView1, canvasView2 } = ref;
return (
<>
<h1>Homepage</h1>
<Link to="/other">Other Page</Link>
<p>Position 1 - Bottle</p>
<div ref={canvasView1} style={{ height: "100px", width: "100px" }} />
<p>Position 2 - Apple</p>
<div ref={canvasView2} style={{ height: "100px", width: "100px" }} />
</>
);
});
OtherPage.js
const OtherPage = React.forwardRef((props, ref) => {
const { canvasView1, canvasView2 } = ref;
return (
<>
<div ref={canvasView1} />
<h1>Other Page</h1>
<Link to="/">Homepage</Link>
<br />
<p>Position 3 - Duck</p>
<div
ref={canvasView2}
style={{
width: "100px",
height: "200px",
display: "inline-block"
}}
/>
</>
);
});
I tried seeing if <Canvas> persists or not (as that could be the cause) by doing a console.log() on the onCreated property of <Canvas>, but it only logs once, so I assume it doesn't get unmounted when I switch pages, so that can't be the cause.
Thank you in advance for any suggestion.

Screen mount twice when I navigate to other screen and quickly re navigate to same screen

I have a problem in navigation lifecycle, which when I navigate from screen to other the last one doesn't stay focus and quickly re navigate to the previous screen. Please if anyone can help me.
This is my AuthStack.tsx file :
import React, { useState, useEffect, useContext } from 'react'
import { createStackNavigator } from "#react-navigation/stack";
import { Text, Button } from 'react-native';
import { Center } from './Center';
import { AuthParamList, AuthNavProps } from "./AuthParamList.ts";
import { AuthContext } from "./AuthProvider";
import { SplashScreen } from "./splashes/SplashScreen";
import {LoginScreen} from './authentificationScreens/LoginScreen'
import {RegisterScreen} from './authentificationScreens/RegisterScreen'
interface AuthStackProps {
}
const Stack = createStackNavigator<AuthParamList>();
export const AuthStack: React.FC<AuthStackProps> = ({}) => {
return (
<Stack.Navigator
screenOptions={{
header: () => {null}
}}
initialRouteName="SplashScreen"
>
<Stack.Screen
options={{ headerShown: false }}
name='SplashScreen'
component={SplashScreen}
/>
<Stack.Screen
name='LoginScreen'
component={LoginScreen}
/>
<Stack.Screen
name='RegisterScreen'
component={RegisterScreen}
/>
</Stack.Navigator>
);
}
and this is the Login Screen :
import React, { useState, useContext, useEffect } from 'react'
import { View, Text, ScrollView, ImageBackground , Dimensions, StyleSheet, Pressable } from 'react-native';
import { Input, ListItem, CheckBox, Button, Switch } from 'react-native-elements';
import { LinearGradient } from 'expo-linear-gradient';
import { AuthParamList, AuthNavProps } from "../AuthParamList.ts";
import { AuthContext } from "../AuthProvider";
import Ionicons from 'react-native-vector-icons/Ionicons';
import * as Animatable from 'react-native-animatable';
import { EventRegister } from "react-native-event-listeners";
import BgGigaFit from "../../assets/background.jpg";
import GigaFitLogo from '../../assets/GigaFitLogo1.png'
interface LoginScreenProps {}
export const LoginScreen: React.FC<LoginScreenProps> = ({ navigation, route }: AuthNavProps<"LoginScreen">) => {
const {login} = useContext(AuthContext);
const [darkMode, setDarkMode] = useState(false);
return (
<ScrollView
style={{flex: 1, backgroundColor: 'darkgray'}}
showsVerticalScrollIndicator={false}
>
<ImageBackground
source={BgGigaFit}
style={{
height: Dimensions.get('window').height / 2.5,
}}
>
{/* <View style={styles.SwitchDarkTheme}>
<ListItem style={styles.SwitchDarkTheme}>
<Switch value={false} color="#52c234"/>
</ListItem>
</View> */}
<View style={styles.brandView}>
{/* <Icon type="FontAwesome" name="home" style={{color: '#ffffff', fontSize: 100}} /> */}
<Ionicons name="md-barbell-outline" size={50} color="#52c234" />
<Animatable.Image
animation="fadeIn"
duration= {4000}
source={GigaFitLogo}
style={styles.logo}
resizeMode="stretch"
/>
</View>
</ImageBackground>
{/*Bottom View*/}
<View style={styles.bottomView}>
{/*Welcome View */}
{/* <View style={styles.SwitchDarkTheme}>
<ListItem>
<Switch value={darkMode} color="#52c234"
onValueChange= {(val) => {
setDarkMode(val);
EventRegister.emit('changeThemeEvent', val)
}}
/>
</ListItem>
</View> */}
<View style={{padding: 40}}>
<Text style={{color: '#52c234', fontSize: 34}}>Welcome</Text>
<Text>Don't have an account yet !!!
<Text onPress={()=> navigation.navigate('RegisterScreen')} style={{color: '#52c234', fontStyle: 'italic'}}>Register Now</Text>
</Text>
{/**Form Inputs View */}
<View style={{marginTop: 50}}>
<Input
placeholder="Email"
rightIcon={<Ionicons name="md-checkmark-done-sharp" size={20} color="#52c234" />}
/>
<Input
placeholder="Password"
rightIcon={<Ionicons name="ios-eye" size={20} color="#52c234" />}
/>
{/**Forgot Password and create new view */}
<View style={styles.forgotPasswordView}>
<View style={{flex: 1, marginTop:-10, marginLeft: -30}}>
<ListItem noBorder>
<CheckBox checked={true} checkedColor="#52c234"/>
<ListItem.Content style={{marginLeft: -35}}>
<Text style={{color: "#52c234"}}>
Remember Me
</Text>
</ListItem.Content>
</ListItem>
</View>
<View style={{flex: 1, marginTop:-3, marginRight: -150}}>
<ListItem noBorder>
<ListItem.Content style={{marginLeft: -40}}>
<Text style={{color: "#52c234"}}>
Forgot Password
</Text>
</ListItem.Content>
</ListItem>
</View>
</View>
{/**Login Button */}
<View style={{height: 100, justifyContent: 'center', alignItems: 'center'}}>
{/* <Button type="Solid" rounded buttonStyle={styles.loginButton}>
<Text style={{color: "#ffffff"}}>Login</Text>
</Button> */}
<Button
icon={
<Ionicons name="md-checkmark-circle-outline" size={20} color="#ffffff" />
}
// title="Login"
type="Outline"
buttonStyle={styles.loginButton}
onPress={() => login()}
/>
</View>
</View>
</View>
</View>
</ScrollView>
);
}
and this is the Register Screen :
import React, { useContext, useEffect } from 'react'
import { AuthParamList, AuthNavProps } from "../AuthParamList.ts";
import { Center } from './../Center';
import { Text, Button } from 'react-native';
interface RegisterScreenProps {}
export const RegisterScreen: React.FC<RegisterScreenProps> = ({ navigation, route }: AuthNavProps<"RegisterScreen">) => {
// useEffect(() => {
// const unsubscribe = navigation.addListener('focus', () => {
// --------------------------------------
// });
// return unsubscribe;
// }, [navigation]);
return (
<Center>
<Text>I am a Register Screen</Text>
<Button title="go to login" onPress={() => {
navigation.navigate('LoginScreen');
// navigation.goBack()
}} />
</Center>
);
}
My Problem is when I navigate from the Login Screen to the Register Screen it just show for a moment and re navigate it self quickly to the login Screen.

How to add multiple divider component in a react navigation drawer

I have a drawer navigation, what I wanted to happen is add divider separating the drawer icon and texts, but I get an error instead
Error is: A navigator can only contain screen components...
Here is my approach:
function DrawerNav(): React$Element<{}> {
return (
<Drawer.Navigator
drawerStyle={styles.drawerStyle}
drawerContentOptions={{
activeTintColor: 'white',
inactiveTintColor: 'white',
activeBackgroundColor: '#163E69',
inactiveBackgroundColor: '#02152B'
}}>
<Drawer.Screen
name="Dashboard"
component={Dashboard}
options={{
drawerIcon: () => (
<Image source = {"assets/icons/dashboard.png"} />
),
}}
/>
<DrawerDivider label="Account" /> // This is my divider component
<Drawer.Screen
name="Profile"
component={Profile}
options={{
drawerIcon: () => (
<Image source={'assets/icons/profile.png'} />
),
}}
/>
<DrawerDivider label="Actions" /> // also my divider component
<Drawer.Screen
name="Settings"
component={Settings}
options={{
drawerIcon: () => (
<Image source={'assets/icons/settings.png'} />
),
}}
/>
<DrawerDivider label="Actions" /> // also my divider component
<Drawer.Screen
name="Logout"
component={Logout}
options={{
drawerIcon: () => (
<Image source={'assets/icons/logout.png'} />
),
}}
/>
</Drawer.Navigator>
);
}
Any suggestions/help are appreciated.
this how I implemented it in my project , you need to create a custom drawerContent component , drawerContent gives incredible amount of flexibility you can literally create what ever you want with it .
Navigator :
import DrawerContent from './DrawerContent'
import { createDrawerNavigator } from '#react-navigation/drawer';
const Navigator =({authenticated,userType})=>{
const Drawer = createDrawerNavigator();
return <Drawer.Navigator
screenOptions={{headerShown:false}}
initialRouteName="INTIALROUTE"
drawerContent={props => <DrawerContent {...props} />}
>
<Drawer.Screen name="route1" component={Screen1} />
<Drawer.Screen name="route1" component={Screen2} />
</Drawer.Navigator>
}
the custom drawerContent component :
import React from 'react'
import {StyleSheet,View,Text,TouchableOpacity} from 'react-native'
import {DrawerContentScrollView,DrawerItem} from '#react-navigation/drawer';
const DrawerContent=(props)=> {
const {navigation}=props
const naviagetToRoute=(e)=>{
navigation.navigate(route)
}
//here you can return diffrent drawerContent based on auth state for example
if(isAuthenticated){
//isAuthenticated can be passed through props using redux's connect or context api
return <View style={{flex:1}}>
<DrawerContentScrollView {...props}>
<TouchableOpacity onPress={naviagetToRoute}>
<View style={styles.drawerItem}>
<Image source = {"assets/icons/logout.png"} />
<Text style={{color:colors.BLACK}} >Logout</Text>
</View>
</TouchableOpacity>
</DrawerContentScrollView>
</View>
}
return (
<View style={{flex:1}}>
<DrawerContentScrollView {...props}>
<TouchableOpacity onPress={naviagetToRoute}>
<View style={styles.drawerItem}>
<Image source = {"assets/icons/dashboard.png"} />
<Text style={{color:colors.BLACK}} >DashBoard</Text>
</View>
</TouchableOpacity>
</DrawerContentScrollView>
</View>
)
}
export default DrawerContent
const styles = StyleSheet.create({
drawerItem: {
display :'flex',
flexDirection:'row',
alignItems:'center',
justifyContent:"space-between",
padding:16,
elevation:12,
backgroundColor:'#fff',
borderRadius:12,
marginBottom:16,
flex:1
}
});

Nested routes with react router v4 not working

I have create a route for a page.In side that page I have use 4 component.I have give path to these to these component.In header dropdown I have given links to these components, On first click the path is change.
but in second click the url is change but not redirecting.
const menu = (
<Dropmenu>
<Menu
key="menu"
style={{ backgroundColor: '#0f2037', borderRadius: '0' }}
>
<Menu.Item key="golive">
<Link to={'/s/live'} style={{ color: '#fff' }}>
<Icon type="video-camera" />
Start Live Broadcast
</Link>
</Menu.Item>
<Menu.Item key="mychannel" style={{ color: '#fff' }}>
<Link to={'/s/profile'} style={{ color: '#fff' }}>
<Icon type="user" />
Manage Profile
</Link>
</Menu.Item>
<Menu.Item key="settings">
<Link to={'/s/account'} style={{ color: '#fff' }}>
<Icon type="setting" />
Account
</Link>
</Menu.Item>
<Menu.Item
key="logout"
onClick={this.logoutCall}
style={{ color: '#fff' }}
>
<Icon type="logout" />
Logout
</Menu.Item>
</Menu>
</Dropmenu>
);
<BrowserRouter>
<Switch>
<Route path="/s" component={GoLive} />
<Route
path="/s/profile"
render={() => (
<div>
<ManageProfile descri={teprop} />
</div>
)}
/>
</Switch>
</BrowserRouter>
Adding exact to Routes will solve the problem:
<Route path="/s" exact={true} component={GoLive} />
<Route
exact={true}
path="/s/profile"
render={() => (
<div>
<ManageProfile descri={teprop} />
</div>
)}
/>
The Switch component renders the first matching route and /s is matched in /s/profile/ .
You can use exact in Route:
<Route exact path="/one" component={About}/>
https://reacttraining.com/react-router/web/api/Route/exact-bool

Resources