React router v6, Remove History - reactjs

Is there a way to remove history in react-router v6, I'm creating a web app, when the user reaches to homepage and presses back it should eventually exit the app. but as of now, it's going back if history exists. if react-router doesn't have this feature is there an alternative way to overcome this issue?

I have just done a PWA app like you and the way I solved this is that I always set option {replace: true} whenever it went forward or backward.
Ex:
navigate(/${SCREEN_1}, { replace: true })
or
navigate(-1, { replace: true })
So when user click on button "Next"/"Back" on the browser, there were only the first blank page of the browser (where before I open my URL) and the current page.
My app only have 6 screens.
I'm not sure whether this way will be useful for you or not, but for me it did.
Hope this help!

I didn't understood your question excatly.
But below code maybe helpful to go back to previous page.
import {useNavigate} from 'react-router-dom'
const Component = () => {
const navigate = useNavigate()
const goBack = () => {
navigate(-1)
}
return (
<>
<button onClick={goBack}>Back</button>
</>
)
}

Related

Preventing goBack with useNavigate hook

Is there a way to prevent back navigation using react's useNavigate hook? I'm currently using navigate("/",{replace: true}) for the time being but would like to have a proper solution for it.
The only way to fight browser's own mechanism like History and navigation is to check history.length:
useEffect(() => {
if (global.history.length> 1) {
window.open(window.location.href, "_blank");
}
}, []);
Imo it's rather confusing. Also when user opens new tab, history.length becomes 1. So code above will not bring another tab only if opened from bookmark/by clicking link with target="_blank".

How to use useNavigate previous page without accidentally leaving my site

Problem: I'm trying to use useNavigate(-1) to go to previous page, but I just implement a way to people arrive in my SPA with a pasted link (or social media tho), so, when user tries to go back they leave my site xP.
Process: I could use useNavigate("/"), but this makes my page scroll to the top and I want to keep the previous users position, I rather not use a state with my scroll position, but if nothing else is possible or simple...
Context: is a restaurant menu ifood-like page, this problems occurs in product page and I want to go back to product list.
What I'm trying to achieve: some way to check if previous page is out of my domain and not go there, replacing with my root.
ps. I'm using "react-router-dom": "^6.0.0-beta.0"
In earlier versions of React Router DOM, there was a smarter goBack method, but in modern versions (including the v6 beta), you must use the fact that the location.key is "default" for the initial entry to the app's history.
I created an npm package that encapsulates this functionality in a simple React hook.
Install use-back
npm install use-back
Usage
import {useBack} from "use-back";
const BackButton = () => {
const {hasBack, handleBack} = useBack();
return (
<button type="button" onClick={handleBack}>
{hasBack ? "Go Back" : "Go Home"}
</button>
);
};
CodeSandbox Demo
Source Code
The source code is basically the following, which you can also include in your application.
const MagicalBack = () => {
const navigate = useNavigate();
const location = useLocation();
const hasPreviousState = location.key !== "default";
const handleClick = () => {
if (hasPreviousState) {
navigate(-1);
} else {
navigate("/");
}
};
return (
<button type="button" onClick={handleClick}>
{hasPreviousState ? "Go Back" : "Go Home"}
</button>
);
};
CodeSandbox Demo

React Router v4 replace history when component is unmounted

I have a app which has the Following Components
|__Base - /home/Base
|__Try - /home/Base/:try
|__Report - /home/Base/:try/report
Base is the Starting screen where the user hits a button and clicks on Try and after trying some things he hits submits which generates reports which has some back end interactions and when the data is fetched it loads the Reports.
So what i want is when the user hits the back button from the Reports Page he should not land on the Try page but on the Base page .
For that to work i went through the react router documentation and was trying to use history.replace on componentWillUnmount for Reports Page
this.props.history.replace(`/home/Base`, {
pathname: `/home/Base`,
search: null,
state: {
isActive: true
}
}, null);
In case the Report Page is FullyLoaded and i press the back button it works but calls the Try Render Method too and then takes me to the Base Page , But in case of Reports Not fully Loaded and i press the back button while the loading spinner is in progress it goes to base page still but also mounts and unmounts the TRY component.
What am i missing here , what causes it to mount/unmount or render the previous component and then load the base component even though i replace the history stack ?
Reason
Related with this issue
React v16, changing routes, componentWillMount of the new route is called before componentWillUnmount of the old route
Update:
Solution (checked, update online demo later)
Use react-router-last-location to get previous pathname
import { BrowserRouter, Switch, Route, Redirect } from 'react-router-dom';
import { LastLocationProvider } from 'react-router-last-location';
<BrowserRouter>
<LastLocationProvider>
<Switch>
...
</Switch>
</LastLocationProvider>
</BrowserRouter>
Check previous pathname in componentWillMount, if it's from certain page, push a new pathname to route.
componentWillMount() {
const { history, lastLocation } = this.props;
if (lastLocation?.pathname === '/home/Base/:try/report') {
history.push({pathname: '/home/Base'});
}
}
You can use the HOC they provide or write it yourself refer to the lib's source to reduce the dependencies
import { withLastLocation } from 'react-router-last-location';
interface Props {
lastLocation: any,
history: any,
}
export const YourComponent = withLastLocation(connect(
...
))
In this way you can redirect all the routing process from certain pages without mount current page, no matter you clicked a back button or clicked the back in your browser.

connect a react-navigation directly to redux?

Is it possible to connect a TabNavigator or a StackNavigator directly to redux?
This is very useful for conditionally navigating to a screen, based on whether or not some condition exists in the Redux store (i.e. if the user is signed in or signed out).
Example:
const Tabs = TabNavigator({
screen: userIsSignedInRedux ? SignedInTabNavigator : SignedOutScreen,
},
});
where userIsSignedInRedux is a key within my Redux store.
It is generally possible, but not recommended, because of the potential performance issues with that approach.
React-navigation had documentation on the topic before but removed it as not recommended in the latest version.
You can check out the following: https://reactnavigation.org/docs/en/redux-integration.html
You can connect a specific view (first inside a navigator) to redux, and inside the componentWillMount method do da redirect if your user is logged in for example.
However, if you have a specific case that would save you time if handled through redux, check out this solution:
https://github.com/react-navigation/react-navigation-redux-helpers
Try this:
import React from 'react';
const TabNavigator = ({ isLoggedIn }) => {
const RouteConfigs = {
Screen: isLoggedIn ? SignedInTabNavigator : SignedOutScreen
};
const Navigator = createBottomTabNavigator(RouteConfigs);
return <Navigator />
};
const mapStateToProps = ({ auth }) => ({ isLoggedIn: auth.isLoggedIn });
export default connect(mapStateToProps)(TabNavigator);
But make to not to render your navigation until the value of isLoggedIn is determined .. cause if not, you're going to see a some kind of flickering effect (SignOutScreen will be rendered and a few moments later you're going to see SignInTabNavigator shows up if isLoggedIn resolved to true)

Are my expectations about React navigation correct?

It might be my lack of understanding, but would anyone explain if my expectations are wrong about React navigation?
My app is more or less a questionnaire where one screen handles all questions. Basically it navigates to itself with a new question ID. That fetches the proper data and displays it. Working fine, but when I press back I do not go to the previous question but to the home page. I use expo and their recommended navigation.
My expectation is when I go back from the last page in :
Homepage => QuestionPage(id=1) => QuestionPage(id=3)
I would go back to QuestionPage with id = 1, but it goes to Homepage. I use withNavigation on both pages to maintain the navigation props.
Is this expectation wrong or is this correct navigation behavior? If so, any clues what to do to get my expected behavior.
To achieve react navigation multi-page application from single page. You need to add "react-router-dom" package in your project.
import {
Route as Router,
Switch,
Redirect
} from 'react-router-dom';
You have to setup router for navigate page as follow.
<Switch>
<Router exact path="/questionpage/:handle" component={Questionpage} />
</Switch>
In Question page Router :
this.props.match.params.handle // will help to get page number
By using above syntax you can get page number and able to get data exact you want.
It was so simple. Instead of
this.props.navigation.navigate('Question', {id=40})}
I had to write
this.props.navigation.push('Question', {id=40})}
If you're using a StackNavigator and from QuestionPage on the back button you do
this.props.navigation.goBack();
instead of
this.props.navigation.navigate('Screen')}
it should work !
If you want to have a custom navigation on a react navigation screen, on the backAndroid I'd recommend to listen to the didFocus like this:
_didFocusSubscription;
_willBlurSubscription;
constructor(props) {
super(props);
this._didFocusSubscription = props.navigation.addListener('didFocus', payload =>
BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
);
}
componentDidMount() {
this._willBlurSubscription = this.props.navigation.addListener('willBlur', payload =>
BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
);
}
hardwareBackPress = () => { this.props.navigation.navigate('Screen')} }
A more accurate example and the documentation regarding it is here https://reactnavigation.org/docs/en/custom-android-back-button-handling.html

Resources