I have a problem that I haven't been able to solve.
In my React native application, I would like to display a welcome screen at the start. Then 5 seconds later just close it, and display another one. Both are 2 entirely different screens, no need to keep the "come back" arrow.
I have been searching for hours, but I haven't found out how to do it.
Here is my code for now:
import Defis from './components/defis'
import Quote from './components/quote'
export default class Betty extends Component {
componentDidMount(){
// Start counting when the page is loaded
this.timeoutHandle = setTimeout(()=>{
// Add your logic for the transition
this.props.navigation.navigate('Defis') // what to push here?
}, 5000);
}
componentWillUnmount(){
clearTimeout(this.timeoutHandle);
}
render() {
return (
<Quote/>
);
}
}
Does anybody know how to do it?
I'm not able to use Navigator.push, moreover Navigator seems deprecated.
Not Using any navigator this can solve your problem
import Defis from './components/defis'
import Quote from './components/quote'
export default class Betty extends Component {
constructor(props){
super(props)
this.state = {
component : <Quote />
}
}
componentDidMount(){
// Start counting when the page is loaded
this.timeoutHandle = setTimeout(()=>{
// Add your logic for the transition
this.setState({ component: <Defis /> })
}, 5000);
}
componentWillUnmount(){
clearTimeout(this.timeoutHandle);
}
render() {
return (
this.state.component
);
I have done this to show login screen after the splash screen in react-native as follows:
import Login from './Login'; // My next screen
....
....
const {navigate} = this.props.navigation;
setTimeout(() => {
navigate('Login'); //this.props.navigation.navigate('Login')
}, 5000); //5000 milliseconds
I have used react-navigation for the navigation purpose.
I was doing almost the same thing with "react-native-router-flux".
Simply render a first screen, in your case the "Quote", and then set in componentDidMount:
setTimeout(() => {
Actions.yourNextSceneName()
}, milliseconds)
Hope this helps.
This worked for me:
import { NavigationActions } from "react-navigation";
componentDidMount(){
setTimeOut( () => {
NavigationActions.navigate('login');
}, 5000 );
}
You can do it with using navigator by returning a View with the onLayout prop and adding the setTimeout function to the prop.
How to navigate to another screen after timeout in React Native:
So I have created my navigation structure and the respective pages already.
Using functional component in ReactNative, do this this to the componentthat you want navigate from:
function MyPresentScreen( {navigation}, props ){
setTimeout(() => {
navigation.navigate('MyTargetScreen');
}, 2500);
return(
<Text>My Present Screen that I will navigate from after some seconds</>
)
};
Note that you can customize the timeout as you wish. The above is 2 and half seconds.
Credit: Even though it was written with class component, this article was helpful in helping me figure this out:
Related
I have created a hamburger menu in react it displays content on breakpoint as expected. But can any body help me to display the hamburger menu icon only on breakpoint otherwise it should display the Navigation menu?
Hey you could use a third-party library like react-responsive and then conditionally render the hamburger menu when a certain device width condition is met. For example, let's say you want to show the <HamburgerMenu /> component when the device with is less than 500px. You could use something like this:
// after installing react-responsive and assuming you have a separate HamburgerMenu and DesktopMenu component
import { useMediaQuery } from 'react-responsive';
import DesktopMenu from './DesktopMenu';
import HamburgerMenu from './Hamburger';
const NavigationMenu = () => {
const isMobile = useMediaQuery({
query: '(max-width: 500px)',
});
return {isMobile ? <HamburgerMenu /> : <DesktopMenu />}
}
---- UPDATE ----
Since you mentioned you don't want to use any third-party libraries, I will add a custom functionality to render components based on window object's innerWidth.
I added a getWindowSize() function that will get the window.innerWidth. Then I will run this function after the page is rendered for the first time using useEffect hook and update the windowsize state. I will also add a resize event to window object to run this function if the window object is being resized. Then based on the windowsize state I will conditionally render what I want (in my example I used 500px as an example. Please see it here:
import { useEffect, useState } from 'react';
import Hamburger from './Hamburger';
import DesktopMenu from './DesktopMenu';
export default function App() {
const [windowSize, setWindowSize] = useState(getWindowSize());
function getWindowSize() {
const { innerWidth } = window;
return { innerWidth };
}
useEffect(() => {
function handleWindowResize() {
setWindowSize(getWindowSize());
}
window.addEventListener('resize', handleWindowResize);
return () => {
window.removeEventListener('resize', handleWindowResize);
};
}, []);
return (
<div>
<h2>Width: {windowSize.innerWidth}</h2>
{windowSize.innerWidth < 500 ? <Hamburger /> : <DesktopMenu />}
</div>
);
}
I'm using react-native, when I try to navigate to another page using StackNavigator the previous page is running on the background
This is App.js
import Login from './app/component/Login';
import Menu from './app/component/Menu';
import Guide from './app/component/additions/Guide';
import { StackNavigator } from 'react-navigation';
const Navigator = StackNavigator({
login: {screen: Login},
main: {screen: Menu},
guide: {screen: Guide},
},{ headerMode: 'none' });
And I have a Guid.js like this
componentDidMount() {
setInterval(() => {
console.log('I do not leak');
}, 1000);
}
render() {
const {navigate} = this.props.navigation;
return(
<TouchableOpacity onPress={() => navigate('main')}>
<Text> navigate to main </Text>
</TouchableOpacity>
)
}
The problem is, even I navigate to the main page, I still getting the interval that I log inside the componentDidMount of my Guide.js, and even going back on that page, it runs the componentDidMount and run again my log, that means the interval is running again, what I want to do is after or while navigating to another page, I want to destroy the Guide.js, the page where I came from, and I have a page where I run WebView I wan't to do the same thing for that page, how can I do that?
Once timers are set, they runs asynchronously, you have to remove the timer if it's no longer needed when you leave the screen, like so:
constructor(props) {
this.timerID = null;
}
componentDidMount() {
this.timerID = setInterval(() => {
console.log('I do not leak');
}, 1000);
}
/**
* Frees up timer if it is set.
*/
componentWillUnmount() {
if (this.timerID != null) {
clearInterval(this.timerID);
}
}
You can load components only when they are needed by using the new React-native Lazy API, here is some documentation on how to use: https://reactjs.org/docs/code-splitting.html
I'm using https://reactnavigation.org/ for navigation in a React Native app with a tab navigator as the main stack and a modal with two screens in it (for logging in and configuring the app).
I can't for the life of me figure out how to close the modal from the second screen (SelectItems). From the first screen in the modal I can close it with navigation.goBack().
Both modal screens need a close button. Is there a way to just return back to whatever tab the user was on?
Thanks in advance for any help.
const Tabs = TabNavigator(
{
Search: { screen: Search },
Settings: { screen: Settings }
}
);
// modal with two screens
const Setup = StackNavigator(
{
Login: {
screen: Login
},
SelectItems: {
screen: SelectItems
}
},
{
initialRouteName: 'Login'
}
);
const RootStack = StackNavigator(
{
Main: {
screen: Tabs
},
Setup: {
screen: Setup
}
},
{
mode: 'modal',
headerMode: 'none'
}
);
I found a solution but it isn't perfect.
You can use the popToTop which will go back to the first Scene of your stack and than the goBack will close the modal.
navigation.popToTop();
navigation.goBack(null);
The problem with that is that it will mount again the first scene of the stack, so be sure you dont use setState in you willMount or didMount. Or prevent it.
That's the solution i'm going with for now. I keep looking for a better solution.
Simple and easy solution for react-navigation 5.x (getParent docs):
navigation.getParent()?.goBack();
This works because it grabs the navigator's parent, which is the modal and what you want to dismiss.
NOTE: In older versions of 5.x this was called dangerouslyGetParent. That exists in newer 5.x versions, but is now deprecated. Use that if getParent isn't available in the version of react-navigation that you're using. It isn't actually dangerous: From react-navigation's documentation:
Reason why the function is called dangerouslyGetParent is to warn developers against overusing it to eg. get parent of parent and other hard-to-follow patterns.
This was my solution with v6 in 2022. It closes the modal and navigates away without any weird behaviors (at least in my case).
onPress = () => {
navigation.goBack(); // <-- this fixed it
navigation.navigate("SomeScreen", { id: 123});
}
If you use react-navigation 4.x there is a method navigation.dismiss(). The method dismisses the entire stack and return to the parent stack
https://reactnavigation.org/docs/4.x/navigation-prop/#dismiss
If you are using Stack Navigation you can always move around in the navigation stack using navigation.pop(). For instance, if you want to close two open modals you can call the pop function with parameter value 2:
navigation.pop(2);
Original solution from https://github.com/react-navigation/react-navigation/issues/686#issuecomment-342766039, updated for React Navigation 4:
Create a DismissableStackNavigator:
import React from 'react';
import { createStackNavigator } from 'react-navigation-stack';
export default function DismissableStackNavigator(routes, options) {
const StackNav = createStackNavigator(routes, options);
const DismissableStackNav = ({navigation, screenProps}) => {
const { state, goBack } = navigation;
const props = {
...screenProps,
dismiss: () => goBack(state.key),
};
return (
<StackNav
screenProps={props}
navigation={navigation}
/>
);
}
DismissableStackNav.router = StackNav.router;
return DismissableStackNav;
};
Usage:
Creating your stack:
// modal with two screens
const Setup = StackNavigator(
{
Login: Login,
SelectItems: SelectItems
},
{
initialRouteName: 'Login'
headerMode: 'none'
}
);
Call navigation.dismiss in your screens to close the modal stack.
I was trying to figure this myself and the solution I ended up using was to use navigation.navigate()
Example this.props.navigation.navigate('name of screen you want to go');
Hope this helps!
I've been trying to call a function which is in a screen of a navigator from its screen.
To clarify the point, here is a snippet of my code...
//ScreenA.js
export default class ScreenA extends React.Component {
showWarning(){
this.setState({showWarning: true});
setTimeout(function() {
this.setState({showWarning: false});
}.bind(this), 3000);
}
render() {
return (
<View style={{backgroundColor : this.state.showWarning ? "#red" : "#blue"}}>
{this.state.showWarning && <Warning />}
</View>
)
}
}
//Nagigator.js
default export const Navigator = StackNavigator({
ScreenA: {screen: ScreenA},
ScreenB: {screen: ScreenB},
});
//App.js
export default class App extends React.Component {
handleSubmit(qrCode){
if(qrCodeIsInvalid){
this.navigator.ScreenA.showWarning();
//This is just a sudo code.
//How do we call ScreenA.showWarning here?
}
}
render() {
let props = {/*some props here*/};
return (//This "ref" stops the application without describing any reason
<Navigator screenProps={props} ref={nav => { this.navigator = nav; }}/>
);
}
}
There is an example of how to call a function from a navigation header, but not from the class which exports the navigator.
I thought that each screen can be accessed via ref, but this causes an error without explaining what's happening.
Has anyone encountered a similar situation?
Any advice will be appreciated.
P.S.
# Nimrod Argov
Here are details of what I've been trying to achieve.
ScreenA has a QR code reader and submit function, which submits QR codes to App.js.
App.js has handleSubmit function, where submitted QR codes are sent to a server and labelled as either valid or invalid.
If a submitted QR code turns out to be invalid, ScreenA has to show a warning message and change its background colour for 3 seconds.
It might be achieved by having App.js pass a prop {showWarning:true} to ScreenA and pass {showWarning:false} in 3 seconds.
However, I thought it would be ScreenA's responsibility to change its background colour. Thus, I set setTimeout and setState in the showWarning().
I did it this way:
ScreenA.js
While navigate to ScreenB, including the function you want to call.
export default class ScreenA extends React.Component {
constructor(props) {
super(props);
this.doSomething = this.doSomething.bind(this);
}
doSomething() {
this.setState({blah: true});
}
navigateToB() {
this.props.navigation.navigate('ScreenB', {
doSomething: this.doSomething,
});
}
}
ScreenB.js
So you can do this in ScreenB.
const { state, setParams, navigate } = this.props.navigation;
const params = state.params || {};
params.doSomething();
I am trying to create a loading screen in React Native that will navigate to a confirmation screen once the time from a setTimeout function has been fulfilled. Currently, the screen loads, but does not navigate to the confirmation screen after the setTimeout interval.
import React from 'react';
import { Text, View, Image } from 'react-native';
import { Actions as NavigationActions } from 'react-native-router-
flux';
import styles from './styles';
export default class ProcessingLoader extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
setTimeout(this.navigateToConfirmation, 3000);
}
navigateToConfirmation() {
NavigationActions.checkoutConfirmation({ product: this.props.product, type: 'reset' });
}
renderLoader() {
return (
<View style={styles.textContainer}>
<Text style={styles.loaderText}>Processing Order ...</Text>
</View>
);
}
render() {
return (
<View style={{ flex: 1 }}>
{this.renderLoader()}
</View>
);
}
}
I've tried using setTimeout in componentDidMount as well as in render. I've also tried using and arrow function vs not using an arrow function. Am I utilizing setTimeout completely wrong here? I'm afraid that I don't understand why it will not navigate to the next screen after 3 seconds. Thanks in advance!
You are not invoking the function, use parenthesis to do that.
Also, the first parameter is a callback, so put your invokation inside a function, like this:
componentDidMount() {
setTimeout(function(t){t.navigateToConfirmation()}, 3000, this);
}
or in an arrow function:
componentDidMount() {
setTimeout(() => {this.navigateToConfirmation()}, 3000);
}