React page does not rerender on url query change - javascript

I'm trying to create a react page having different content based on the query in the url. ex: things?type=0 and things?type=1 resulting in different filtered content.
The problem is, React isn't triggering a rerender of my page when switching to these pages. I need to manually refresh the page to get the desired result.
I tried to use the build in lifecycle features but non of them triggers the page to refresh. It tried to do my fetch in the componentWillReceiveProps method with then I have to click twice on the link to get my filtered content (which is better than no page refresh but not user friendly).
I use this reference.

You will probably want to use https://github.com/reactjs/react-router or some similar library for routes.
If you want to go on your own you have to listen to browser history changes. You could do it like this for example:
componentDidMount: function () {
var component = this;
window.onpopstate = function() {
console.log(window.history.state);
component.setState({
query: window.location.search
});
};
};
I am not sure if this is the good way to go, but it should work at least.

Related

Router.push or Link not rendering/refreshing the page even thought the url is updated nextjs

I apologize for my horrendous way of explaining my issue. I have shared a link below description which is exactly the same issue I am experiencing. Any kind of help would be greatly appreciated.
I have directory path like pages/request/[reqid].js . When my url is localhost:3000/xyz and I navigate to pages/request/1 by clicking a button on the current page, the page successfully loads the page with proper data from [reqid=1] but when I try to access pages/request/[reqid].js with different reqid (say suppose reqid=2), the url reflects the correct the reqid pages/request/2 but the page remains the same, doesn't change. However if I go back to other pages like localhost:3000/xyz and click a button there to navigate to pages/request/2 it works but from within pages/request/[reqid] it doesn't render a page associated to the corresponding reqid even thought the url is updated. I have tried both Link and router.push ,both fails to render the correct reqid page.
https://github.com/vercel/next.js/issues/26270
It actually failed to include that I was using getServerProps to fetch the data, which was the reason the page wasn't rendering , unless the page was manually refreshed. The page state is not reset for navigation between dynamic routes that served by the same source component.
for example, give page source /a/[param]/index.js, when navigating from /test/123 to /test/124, states on the page wasn't being reset.
So actually happened is the same React Component been rendered with different props. Thus react takes it as a component is rerendering itself, and causing the new navigated page receive stale states.
To fix it, just add {key: } to page initial props or getserversideprops
export const getServerSideProps = async (ctx) => {
try {
const { reqid } = ctx.params;
//fetch code
return {
props: {
key: reqid,
data:data
},
};
} catch (error) {
console.log(error);
}
};

Persist state after reload in react

Once I go to a particular page by passing in props to that page I want to be able to reload the page without losing the state, currently, when I reload, the page throws an error, that the prop is missing.
For example if I use
history.push({ pathname: '/animal-details',animal_id: animal.id })
it shows the details on these next page but when I reload the page the data goes away and the page is left blank. How to get around this?
Thank You.
Aside from using localStorage or cookies, I think this is a good situation to just make the animal_id part of the path.
Instead of doing
history.push({ pathname: '/animal-details',animal_id: animal.id })
I would do:
history.push(`/animal-details/${animal.id}`)
using a template literal.
If you're using react-router-dom, you can get the animal id using the location prop or the useLocation hook.
const path = props.location.pathname.split('/')
const animalId = path[path.length - 1] // the animal id is the last value in the array
If you aren't using react-router-dom for whatever reason, you can also do something similar using vanilla js window.location.href.
You can use:
localStorage
localStorage.getItem('yourData');
or
Cookies
https://www.npmjs.com/package/react-cookie

history.push using react-router-dom

I am navigating from one page to another using history.push which is available from below
import { withRouter } from 'react-router-dom
I am able to navigate properly but i have a requirement that if i move from Page A to Page B, i should not be allowed to go back to previous page using Browser back button.
I know this can be achieved by window.redirect but i dont want to use that. The problem with that is the entire state and redux store information is lost. Does anyone know if i can use withRouter and still be able to achieve the requirement above.
You could use the history.replace('/Whatever_screen') to replace the current page in the stack.
replace(path, [state]) - (function) Replaces the current entry on the history stack.
Second option:
You could use the below code to block the user to going back in the history.
componentDidMount() {
const { history } = this.props;
window.onpopstate = function (event) {
history.go(1);
};
}
Working Example:
MDN reference here:
There is no way to clear the session history or to disable the back/forward navigation from unprivileged code. The closest available solution is the location.replace() method, which replaces the current item of the session history with the provided URL.

Want to have an event handler for the browser's back button with next.js

I am having a modal which while opening pushes a hash to url example.com/#modal, on browser back button click, I want to recognise that event so that I can toggle the state of modal. the point is, since Im using it with next.js (server side rendering), I will not be having access to window object (correct me if I am wrong). so I need an alternate way to handle the event of browser back button.
You can use next/router's beforePopState to act on changes to the session history navigation (back/forward actions), and make sure it'll only happen when leaving the current page.
useEffect(() => {
router.beforePopState(({ as }) => {
if (as !== router.asPath) {
// Will run when leaving the current page; on back/forward actions
// Add your logic here, like toggling the modal state
}
return true;
});
return () => {
router.beforePopState(() => true);
};
}, [router]); // Add any state variables to dependencies array if needed.
#Summy I hope your issue is resolved by now. If not you can try this for the browser back button:-
Next.js + React Go back to the previous page
If you want to use hashbang URLs you can't use SSR, since /# and /#/one is the same route server-side, so there is no way for the server to know what to render, it will need to send a basic template and let the client fill it, in that case, I think using CRA or Parcel with React Router and its HashRouter is a better option, that way you will have a single index.html and let the client decide what to render.
in NextJs we can use beforePopState function and do what we want such close modal or show a modal or check the back address and decide what to do
https://stackoverflow.com/a/60702584/4717739
https://stackoverflow.com/a/69560739/4717739

Passing Huge data between Vue js routes

I have an application which searches for flights using Vue.js and Vue Router.
I have two components, first one is search, which is on the base route '/'. When user clicks on search, it will send a request to server and gets a huge list of flights.
Then I need to call the result component on '/results' route and show the results using v-for.
I have two questions, first, how can I manually redirect to '/results' after I get the results.
Second and more important, what is the proper way of passing the results data to results component to use?
Inside your results components, you can put transition hooks in the route object. Read here: http://vuejs.github.io/vue-router/en/pipeline/hooks.html
The activate hook runs when a component is activated, and the component wont appear until the activate hook has run. Here's the example on that page, which would be similar to yours:
route:{
activate: function (transition) {
return messageService
.fetch(transition.to.params.messageId)
.then((message) => {
// set the data once it arrives.
// the component will not display until this
// is done.
this.message = message
})
}
}
So basically when they click search you send them to /results and this hook will handle loading the data in between.
Here's an advanced example of a mail app using vue-router that shows off a lot of the transition hooks in action: https://github.com/vuejs/vue-router/tree/dev/example/advanced

Categories