I'm looking at using React-Native and Expo to build a web app. The only real issue I'm running into is allowing the use of the browser back button. I'm currently using #react-navigation/native to navigate between screens.
Unfortunately, when changing screens, the browser doesn't seem to register this as a change of page and so the browser back button never works. I could certainly use the standard back button used within the app to navigate back but I'd like people to be able to use the browser back button as that's more intuitive. I'm using the following in my App.js:
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
const Stack = createNativeStackNavigator();
const App = () => {
...
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Settings"
component={SettingsScreen}
options={{ headerShown: false }}
/>
</Stack.Navigator>
</NavigationContainer>
)
};
export default () => {
return (
<App />
);
};
So, is it possible using Expo and React-Native to allow the use of the browser back button for apps built for the web?
Related
I'm using React Navigation 6.x's linking with Expo so that when a user clicks on a notification they are directed to the appropriate part of my application to interact with the new information. When my app is backgrounded (running in the background) and a user clicks on a notification they are redirected to the screen they need to be at, which works perfectly fine. However, when the app is killed and the user clicks on a notification, they are taken directly to the screen for which the url is provided and they cannot press back to navigate elsewhere in my application. I tried to resolve this by using the initialRouteName prop like is shown in the docs (link: https://reactnavigation.org/docs/configuring-links/#rendering-an-initial-route), but I cannot get it to work. For further clarification, when I mentioned above that I am able to get linking working it is in relation to the direct SettingsScreen, AddFriendScreen, and MessagingScreen links. What I cannot get working is the specific block of code inside the liking object that starts with HomeScreen. What I believe may be causing the issue is that I am trying to set my initialRoute as a screen within HomeScreen's Tabs.Navigator and then trying to route to a screen within my Stack.Navigator. However, the docs show that this is possible (link: https://reactnavigation.org/docs/configuring-links/#rendering-an-initial-route).
My code:
const linking = {
prefixes: [prefix],
config: {
screens: {
HomeScreen: {
initialRouteName: "Chats",
screens: {
AddFriendScreen: "addFriend",
CreateChatScreen: "createChatScreen",
Friends: "friends",
MessagingScreen: 'messagingScreen/:chatRoomId'
}
},
SettingsScreen: "SettingsScreen",
AddFriendScreen: "AddFriendScreen",
MessagingScreen: 'MessagingScreen/:chatRoomId'
},
}
};
<NavigationContainer linking={linking} theme={MyTheme} >
<Stack.Navigator>
{!authState.value ?
<>
<Stack.Screen name="LoginScreen" component={LoginScreen} />
<Stack.Screen name="SignUpScreen" component={SignUpScreen} />
<Stack.Screen name="ForgotPasswordScreen" component={ForgotPasswordScreen} />
</>
:
<>
<Stack.Screen name="HomeScreen" component={HomeScreen} />
<Stack.Screen name="MessagingScreen" component={MessagingScreen} />
<Stack.Screen name="SettingsScreen" component={SettingsScreen} />
<Stack.Screen name="CreateChatScreen" component={CreateChatScreen} />
<Stack.Screen name="AddFriendScreen" component={AddFriendScreen} />
</>
}
</Stack.Navigator>
</NavigationContainer>
const HomeScreen = () => {
return (
<Tabs.Navigator>
<Tabs.Screen name="Chats" component={ChatScreen} />
<Tabs.Screen name="Friends" component={FriendsScreen} />
<Tabs.Screen name="Profile" component={ProfileScreen} />
</Tabs.Navigator>
)
}
Hmm, I would put any screen that I would like to access in multiple navigators at the root level so that they can both reach it.
For my own project, I have a root stack with a dedicated auth stack and an app/home stack (which is a tab nav like your HomeScreen). And outside that I have all my modal and root screens that I'd like other navigators to access (Because I really have two Home tab navigators the user can switch between.)
Idk if putting all of your screens listed after HomeScreen outside of that object will help your situation, but you can try that.
I have a project in react native in which I wanted to implement a feature.
I have three screens
slash screen
login screen
home screen
the slash screens last 1 second and leave on the home screen while the number of times the app has been opened does not exceed 3 times.
otherwise we display the login screen to ask for a password
About how to make the splash screen last 1 second, on Splash component, put an useEffect like this:
function Splash({ navigation }) {
useEffect(() => setTimeout(navigation.navigate('Home')),[]);
return (
<View>
<Image />
</View>
);
}
About conditional first screen when open the app, you can pass initialRouteName as a prop of Stack.Navigator:
import { createStackNavigator } from '#react-navigation/stack';
const Stack = createStackNavigator();
function App() {
return (
<Stack.Navigator initialRouteName={times < 3 ? Slash : Login}>
<Stack.Screen name="Slash" component={Slash} />
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Login" component={Login} />
</Stack.Navigator>
);
}
Note: my examples above use StackNavigator and on React Navigation v6, it works the same as TabNavigator and other versions of React Navigation.
I am building a React Native project with Expo. For navigation, I am using react-navigation 6.0 with the following code for my main component:
export default class App extends Component {
render() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName={'SignIn'} screenOptions={{
headerShown: false
}}>
<Stack.Screen name="SignIn" component={SigninScr} />
<Stack.Screen name="SignUp" component={SignupScr} />
<Stack.Screen name="EmailVerification" component={EmailVerificationScr} />
</Stack.Navigator>
</NavigationContainer>
);
}
}
This works fine, but I haven't been able to make Stack.Navigator cover the entire screen. There is a weird area that's not covered by the Stack.Navigator:
I was reading through some of the documentation about stack navigator, but couldn't find any props or styling to force it to cover 100% of the screen. Does anyone know how to accomplish this?
For some reason I can see the elements when run on web (using Expo) and they render perfectly when I click "Run in web browser".
However when I try to do it on iOS or Android, it just shows a blank screen and only shows the LinearGradient.
When I run the Android Emulator and combine it with the React Native Dev tool, I can see the elements in the devtool but they dont show up in the emulator. The component I try to render is called Login.tsx and If i copy all the content in Login.tsx to my App.tsx it renders perfectly on Web, Android and iOS.
What am I doing wrong?
const Stack = createNativeStackNavigator();
const Navigation: React.FC = () => {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Login"
>
<Stack.Screen
name="Login"
component={Login}
/>
<Stack.Screen
name="LostPassword"
component={LostPassword}
/>
<Stack.Screen
name="Register"
component={Register}
/>
</Stack.Navigator>
</NavigationContainer>)
}
export default Navigation;
const App: React.FC = () => {
return (
<LinearGradient
colors={["#2D1C96", '#190E60']}
style={styles.linearGradient}
>
<View style={styles.container}>
<Navigation />
<Toast ref={(ref) => Toast.setRef(ref)} />
</View>
</LinearGradient>
);
}
Solved it.
For anyone facing the same issue:
NavigationContainer should not be inside View. It should be used as a root component
Building my first React Native Application.
Currently I am using this way of navigating through different views.
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name={"Start"} component={Welcome}/>
<Stack.Screen name={"LoginMethod"} component={LoginMethod}/>
<Stack.Screen name={"SocialSecurityNumber"} component={SocialSecurityNumber}/>
<Stack.Screen name={"NorBankId"} component={NorBankId}/>
<Stack.Screen name={"NorBankIdMobile"} component={NorBankIdMobile}/>
<Stack.Screen name={"NorBankIdMobileUsername"} component={NorBankIdMobileUsername}/>
<Stack.Screen name={"NorBankIdMobilePassword"} component={NorBankIdMobilePassword}/>
<Stack.Screen name={"Fingerprint"} component={Fingerprint}/>
<Stack.Screen name={"MainView"} component={MainView}/>
</Stack.Navigator>
</NavigationContainer>
This setup, is for the onboarding process from a new customer.
So the first component is Welcome and then the user moves along, with the option to go backwards.
However, when they are done with the process (the last screen), I want them to arrive to a "Screen" that is not ontop of the Stack, but it's own "Root" or "Base" View.
What I have looked into
I have tried having multiple stack navigators which is a no no. Also checked the Tab navigator, however this creates a tab menu below me screen, which I do not want.
Is it possible to do what I want, or do I need to restructure the way I have my setup now?
Thank you for your time, Stay Safe!
Why you don't want to use multiple Stack-Navigators?
My approach would be:
<NavigationContainer>
{ inWelcomeProcess && <WelcomeNavigator/>}
<AuthNavigator/>
</NavigationContainer>
const AuthStackNavigator = createStackNavigator();
export const AuthNavigator = () => {
return (
<AuthStackNavigator.Navigator screenOptions={defaultNavOptions}>
<AuthStackNavigator.Screen name="Auth" component={AuthScreen} options={authScreenOptions}/>
// Your other screens (after finishing the on-boarding) should go here
</AuthStackNavigator.Navigator>
);
};
const WelcomeStackNavigator= createStackNavigator();
export const WelcomeNavigator= () => {
return (
<WelcomeStackNavigator.Navigator screenOptions={defaultNavOptions}>
// Your On-Boarding process screens here
</WelcomeStackNavigator.Navigator>
);
};