Reputation: 19660
In react i need to be able to open a popup window https://developer.mozilla.org/en-US/docs/Web/API/Window/open and manage the events such as "mesage" https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage and "load" and "close" events.
However none of the events i have added listeners to are firing...
import * as React from 'react';
import './style.css';
import { useState, useRef } from 'react';
export default function App() {
const { login, error } = useOAuth();
return (
<div>
<button onClick={login}>Login</button>
</div>
);
}
const useOAuth = () => {
const [error, setError] = useState();
const popupRef = useRef<Window | null | undefined>();
const login = () => {
popupRef.current = openPopup('https://google.com');
popupRef.current.addEventListener('load', handlePopupLoad);
popupRef.current.addEventListener('close', handlePopupClose);
popupRef.current.addEventListener('message', handlePopupMessage);
};
const handlePopupLoad = (data) => {
console.log('load', data);
};
const handlePopupClose = (data) => {
console.log('close', data);
};
const handlePopupMessage = (data) => {
console.log('message', data);
};
const openPopup = (url: string) => {
const params = `scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,
width=500,height=600,left=100,top=100`;
return window.open(url, 'Login', params);
};
return {
login,
error,
};
};
https://stackblitz.com/edit/react-ts-qlfw9q?file=App.tsx
aside:
Upvotes: 2
Views: 3113
Reputation: 5388
I have changed the URL to a local one (to avoid any cross-origin issues).
Check out the demo (If this fails to load, try refreshing. Something seems to be off with Stackblitz)
In parent page, I have used the onload
(for loading), onunload
(for close)
import * as React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/auth" element={<AuthPage />} />
</Routes>
</BrowserRouter>
);
}
function Home() {
const login = () => {
console.clear();
const url = '/auth';
const popup = openPopup(url);
// When the popup loads
popup.onload = () => {
console.log('loaded. this was logged');
};
// when the popup unloads
popup.onunload = () => {
console.log('unloading now');
};
// when the popup posts a message
popup.addEventListener('message', ({ data }) => {
console.log('message: ', data);
});
};
const openPopup = (url: string) => {
const params = `scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,
width=500,height=600,left=100,top=100`;
return window.open(url, 'Login', params);
};
return (
<div>
<h1>Home</h1>
<button onClick={login}>Login</button>
</div>
);
}
function AuthPage() {
// I have added a button to trigger postMessage to parent.
const onClick = () => {
window.parent.postMessage('To parent');
};
return (
<div>
<h1>Auth Page</h1>
<button onClick={onClick}>Click me</button>
</div>
);
}
Few things I observed:
window.addEventListener('message')
to get triggered. But, for some reason, is popupRef.current.addEventListener('message')
getting triggered.popupRef.current.onunload
gets triggered before the beginning of onload
. If I had to guess, this is some sort of cleanup mechanism.Upvotes: 1
Reputation: 132
well, you should probably wrap all your event listeners inside a useEffect
to run it and cleanup after it, it should look like something like this
const popupRef = useRef<Window | null>(null)
const handlePopupLoad = (data: any) => {
console.log('load', data)
}
const handlePopupClose = (data: any) => {
console.log('close', data)
}
const handlePopupMessage = (data: any) => {
console.log('message', data)
}
const openPopup = (url: string) => {
const params = `scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,
width=500,height=600,left=100,top=100`
return window.open(url, 'Login', params)
}
useEffect(() => {
if (!popupRef.current) {
return undefined
}
popupRef.current = openPopup('https://google.com')
popupRef.current?.addEventListener('load', handlePopupLoad)
popupRef.current?.addEventListener('close', handlePopupClose)
popupRef.current?.addEventListener('message', handlePopupMessage)
return () => {
popupRef.current?.removeEventListener('load', handlePopupLoad)
popupRef.current?.removeEventListener('close', handlePopupClose)
popupRef.current?.removeEventListener('message', handlePopupMessage)
}
}, [popupRef])
Upvotes: 0
Reputation: 109
I think there is no react specific issue all you need to do to make this code work is to change your login function something like this.
const login = () => {
const childWindow = openPopup('https://same-origin.com');
childWindow.addEventListener('load', handlePopupLoad);
childWindow.addEventListener('close', handlePopupClose);
childWindow.addEventListener('message', handlePopupMessage);
};
Upvotes: 0