I'm trying to build an OAuth2 sign in flow in my React app using Google as my Auth provider.
To do this, when a user hits 'login',I open up a new window and direct the user to Google to sign in. (I use this npm package https://www.npmjs.com/package/react-new-window to do so)
I want to close this pop up window when a user has signed in successfully, to check for a successful sign in I want to keep track of the URL in the pop up window (which will change to a redirect URL indicating login success). I keep track of the New Window by assigning a ref to it from the parent component.
var newWindowRef = React.createRef();
return (
<NewWindow
ref={newWindowRef}
url="http://localhost:8080/oauth2/authorization/google"
>
</NewWindow>
)
How can I keep track of the URL in the new Window?
https://www.gethugames.in/2012/04/authentication-and-authorization-for-google-apis-in-javascript-popup-window-tutorial.html -> this post suggests using an interval timer, but this seems crude.
I've also tried using a hook in the parent component:
useEffect(() => {
console.log("New Window URL Changed");
console.log(newWindowRef.current.window.document.URL);
}, [newWindowRef.current.window.document.URL]);
The problem here is that newWindowRef.current is null when the parent component is first rendered, and this errors out: "TypeError: newWindowRef.current is null"
Related
I have a "settings" page in my react app. The page has several tabs rendering different parts of settings.
It would be better UX if a user can share urls with other users.
What I want is (inside "settings" page):
user A clicks a tab
url changes with a #tabname appended
user A send that url to user B, and user B open that url
user B sees the same tab as user A
But with react router, the whole page re-renders if the url changed:
import { withRouter } from "react-router-dom"
const MyComp = (props) => {
...
const onTabChange = () => {
// append #tabname here
props.history.replace(...); // or `push`
...
}
...
export default withRouter(MyComp)
}
After a lot of searches, I found a solution to use window.history:
const onTabChange = () => {
window.history.pushState(null, null, "#tabname");
...
}
This does the trick, but little information and explanation, and I'd love to know the consequences of using this trick.
Is this a valid solution (for a react app)? Will this cause any problem?
(PS. I know how to parse a url)
More details:
To be more specific, there is a AuthChecker wrapper for all pages. When react router's location changes, it checks for the route's allowed auths and current user's auth.
I've tried /path/:id and everything but all change location, so auth checked and page rerendered.
And I've given up a solution in react router and just want to know: is it safe to change url with window.history in a react app using react router to manage routes?
this question is already answerd at this post.
so it says window has a property called history and there is a method on history which helps you update the history state without react-router-dom understanding it.
like this:
window.history.replaceState(null, 'New Page Title', '/new_url');
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.
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
I'm using React-Router's Prompt component to block a user from switching tabs when a form is in a dirty state. Each tab has its own route and I'm using history.push to update the URL. Prompt shows up as expected when the form is dirty, but the user is still taken to the new URL when they click "cancel".
Here is the function that handles switching tabs and updating the URL.
const handleClick = (tabId, disabled, route) => {
if (disabled) {
return false;
}
setSelectedIndex(tabId);
if (route) {
history.push(route);
}
return true;
};
I'm guessing that history.push gets executed not matter what.
Every example I see of using Prompt shows it being used with Link. Is there a way to get Prompt to work with history.push?
Inside my app.component , I have a background mode service which when shared via intent throws value to a behaviour Subject
this._notification.setNotiService2(data.extras);
Once logged In , I am setting the root to TabsPage
this.appCtrl.getRootNav().setRoot('TabsPage');
On Tabs Page , I have subscribed to the behaviour subject , so whenever I get a shared object , I process it and open a Modal displaying the required values.
Initally when the app opens , everything works fine. But once we login/logout the problem occurs. On logging out , I am setting the root page as Login Page.
this.appCtrl.getRootNav().setRoot('LoginPage');
Then again on successful login setting root to Tabs Page
this.appCtrl.getRootNav().setRoot('TabsPage');
Now again if I share the values via intent multiple instances of the Modal are opening with the exact same values.
I have checked for behaviour subject as being null/undefined but the subscribed value is Ok only . Logging the value from behaviour Subject inside the TabsPage , I found the same function (subscribed behaviour subject) is being called twice.
Again if I logout/login the Modal opens 3 times and the number continues to grow accordingly.
It sounds to me, that you are not remembering to unsubscribe, which means that the subscriptions increment each time. So whenever you leave a page, remember to unsubscribe to (all) your subscriptions. Since you are using Ionic, the ionViewWillLeave hook would be a suitable place to unsubscribe... so declare a new Subscription on your page and...
import { Subscription } from 'rxjs/Subscription';
// ...
mySubscription = new Subscription();
// ...
this.mySubscription = this.myService.mySubject.subscribe(....)
// ...
ionViewWillLeave() {
this.mySubscription.unsubscribe();
}