When Is A Good Time To Use React Router Replace(componentDidMount?) - reactjs

I have a component that if someone would copy the url and page it in a new tab would crash as it is missing data required from a pervious step.
I want to redirect them to some other page and remove it from their "back" history. So I was thinking of using "replace"
I been doing it on componentDidMount but noticed everything just seems to run twice.
// Page1Component
componentDidMount(){
if(true){
const { replace } = props.routingStore;
const params = props.match.params;
replace('/members/home')
}
}
So when the above code gets hit, this is what happens
Page1Component componentDidMount loads
HomeComponent componentDidMount loads
Page1Component componentDidMount loads again
HomeComponent componentDidMount loads

you can use the Redirect component directly in the render method :
if(...) {
return <Redirect to="/members/home" push={false}/>;
}
Note that using push={false} will replace the current entry into the history

Related

ComponentDidMount did not fire after using Redirect in react-router

so i was using redirect in react-router-dom, i have 2 pages, home and create when the form in create is done and has been submitted, it will execute the <Redirect> function, and it works, but the ComponentDidMount was not being fired again, i need to reload the page to make the ComponentDidMount to make it start again, here is my code
this is how i redirect in the Create file :
if(this.state.createNew){
return <Redirect to='/home'/>
}
and this is my ComponentDidMount in my Home file :
componentDidMount() {
console.log("hi")
}
the console print hi only on the initial render, when i redirect back to the page it does not fire again, i tried use setState inside the ComponentDidMount but it still not being re rendered.
when i tried using Link to method, it works, the ComponentDidMount is being fired again, but Link to is not what i want, because it does not automatically redirect like the <Redirect> do
i got an error when i try to use the useHistory function :
React Hook "useHistory" is called in function "simpan" which is neither a React function component or a custom React Hook function react-hooks/rules-of-hooks
here is how i use my useHistory :
function simpan(event){
event.preventDefault()
const email = event.target.elements.email.value
const name = event.target.elements.name.value
const admin = event.target.elements.admin.value
const active = event.target.elements.active.value
const history = useHistory()
console.log(email)
history.push('/home')
}
thanks before, anyhelp will be appriciated
instead of <Redirect /> why don't you use history.push('/home'). this will take you to the new route once state is true and call componentDidMount
how to use history:
import { useHistory } from 'react-router-dom'
then inside your component: const history = useHistory()
then whether you need to change the route:
history.push('/home')
If your create is class component just use this.props.history.push("/home") instead of <Redirect> tag.
As create component is your route it will automatically get history object in props.
why to use history instead of redirect tag in your case
Simple example of programatic navigation with react routing Please check console of browser while checking this example

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.

Where to Put Code that should run First ReactJs + Mobx State Tree

I have some code that grabs the users ipAddres. I do this right now in my componentDidMount in my app.js
async componentDidMount() {
await eventTrackingStore.getIpAddress();
}
So I did it in my app.js as it is my root component and I only want to set this once. This works fine if the user starts from the home page and navigates through the site.
However some pages can be loaded directly(ie you type in the url in your browser and it goes straight to that page).
Since the react lifecycle starts with most immediate component, which calls a method that expects the ipAddress code to be set but it does not get set till it hits the app.js
Now I could put the above code in each method but that gets tedious. Is there some sort of method in reactjs, or mbox or mbox state tree that would fire first?
If you use mobx-state-tree and you have a global store, then that global store can make the API call in the afterCreate method
const AppModel = types.model({
ips: types.array(types.string)
}).actions(self => ({
afterCreate() {
flow(function*() {
const ips = yield eventTrackingStore.getIpAddress();
self.setIps(ips)
})()
},
setIps(ips: string[]) {
self.ips = ips
}
}))
OR
The same thing you can do in a wrapped react component that wrappes every page of your app.
class App extends React.Component {
componentDidMount() {
eventTrackingStore.getIpAddress().then(res => {
// set the ips into a store or any logic you want in order to pass them down to children
})
}
render() {
return this.props.children
}
}
I can think of two solutions:
You can use react context
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
Use context to share the store between all components and if the data is not loaded, initialize loading right there in that nested component.
If the data is already there then just take it,
getIpAddress method should return a promise, so in case when data is already there it will be immediately resolved.

How to refresh a component after already visiting it?

Working on a project and when changing routes, coming back to one after already visiting it doesnt display new changes/additions. For example, if i route to my "Offers" route, it will display my offers on current items for rent. If i then leave that route and go and place another offer on an item, routing back to "Offers" will reveal no changes unless I refresh the page. I populate the state in componentdidmount() but have also tried other ways where im not using componentdidmount() to populate it. What options do I have here? I can post the component if needed.
Going back to a route which was already visited in the same BrowserRouter context, will not MOUNT the component again. It would only cause the router to perform a pop action, which causes the browser to pop the latest DOM generated for that route to pop from the router context. So what you would have to do, is to check if the user has pressed back button in his/her browser. To do so, you can check this.props.history.action === 'POP' in componentWillReceiveProps lifecycle. Something like this:
class Offers extends Component {
constuctor (props) {
super(props);
this.state = {
offers: []
}
}
componentDidMount () {
this.fetchOffersAndStoreThemInState();
}
componentWillReceiveProps () {
if (this.props.history.action === 'POP') {
this.fetchOffersAndStoreThemInState();
}
}
}
And don't forget to wrap your component with withRouter to have access to the history object.

React-Router: Apply logic to component before navigating to a different route

Is it possible to apply logic to a component before navigating to a different route?
For example, my component looks something like this:
class Example extends React.Component {
//Handles logic for when user leaves page
handlePageExit = () => {
console.log("Leaving page...");
}
//Set onBeforeUnload event listener so handlePageExit function is called when user closes or refreshes page
componentDidMount = () => {
window.addEventListener("onbeforeunload", this.handlePageExit);
}
//This hook is called when page exits or is refreshed
//It will remove event listener when
//However, it wont be called when user changes to a new route
componentWillMount = () => {
window.removeEventListener("onbeforeunload", this.handlePageExit)
}
//There's no react life cycle hook I can use to call HandlePageLogic when user navigates to a new route to remove event listener or apply other logic...
render(){
return(
<div /> //Not relevant to question
)
}
}
I'm trying to apply logic such as removing event listeners before the page is navigated to the new route.
I've tried using life cycle methods such as componentWillReceiveProps, componentWillUnmount, and componentShouldUpdate to insert logic before the component is unmounted however they don't seem to be invoked when navigating to a new page.
Does anyone know where or how I can insert logic in between a route change in react-router v4?
Thank you.
Yes, it is.
You need to add a change listener to you react router history object.
To do this add in your componentDidMount that has the history prop:
componentDidMount() {
this.props.history.listen(this.onRouteChange.bind(this));
}
onRouteChange(route) {
//route.pathname = Your next route
//Handle what you need to do here
//if you need to redirect you can do this
this.props.history.replace({pathname: '/desiredRoute'});
}

Resources