I am using sessionStorage to keep the auth information and need to replicate this information to other tabs being opened. I have created a codesandbox to recreate the issue. I didn't include code in this post since it is quite lengthy.
When the Dashboard link is opened in another window, it is not rendered due to the error being popped up.
EDIT: I have included all the necessary codes below.
App.js
export default function App() {
return (
<>
<Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/login">
<Login />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
</Switch>
</Router>
</>
);
}
Dashboard.js
export default (props) => {
const [isLogged, setIsLogged] = useState(false);
const [email, setEmail] = useState();
const [token, setToken] = useState();
const authChannel = new BroadcastChannel("auth");
useEffect(() => {
setToken(sessionStorage.getItem("token"));
setEmail(sessionStorage.getItem("email"));
setIsLogged(sessionStorage.getItem("token") ? true : false);
authChannel.postMessage({ action: "created", source: "Dashboard" });
}, []);
useEffect(() => {
authChannel.onmessage = function (e) {
if (
e.data.action === "login" &&
(e.data.target === "*" || e.data.target === "Dashboard")
) {
setIsLogged(true);
setEmail(e.data.data.user.email);
setToken(e.data.data.token);
sessionStorage.setItem("email", e.data.data.user.email);
sessionStorage.setItem("token", e.data.data.token);
}
};
}, [authChannel]);
return (
<>
<h1>Dashboard</h1>
{isLogged && <h1>You are logged in</h1>}
{!isLogged && <h1>Please log in</h1>}
</>
);
};
Home.js
import React, { useState, useEffect } from "react";
export default (props) => {
const [isLogged, setIsLogged] = useState(false);
const [email, setEmail] = useState();
const [token, setToken] = useState();
const [user, setUser] = useState();
const authChannel = new BroadcastChannel("auth");
useEffect(() => {
setToken(sessionStorage.getItem("token"));
setEmail(sessionStorage.getItem("email"));
setIsLogged(sessionStorage.getItem("token") ? true : false);
}, []);
useEffect(() => {
authChannel.onmessage = function (e) {
if (
e.data.action === "login" &&
(e.data.target === "*" || e.data.target === "Home")
) {
setIsLogged(true);
setEmail(e.data.data.user.email);
setToken(e.data.data.token);
setUser(e.data.data.user);
sessionStorage.setItem("email", e.data.data.user.email);
sessionStorage.setItem("token", e.data.data.token);
} else if (e.data.action === "created") {
authChannel.postMessage({
action: "login",
target: e.data.source,
data: { user: user, token: token }
});
}
};
}, [authChannel]);
const logout = () => {
setIsLogged(false);
setToken(null);
setUser({});
setEmail();
sessionStorage.removeItem("email");
sessionStorage.removeItem("token");
};
return (
<p>
{isLogged && (
<>
<p>
<a href="/dashboard">Dashboard</a>
</p>
<button onClick={() => logout()}>logout</button>
</>
)}
{!isLogged && (
<>
<p>
Please <a href="/login">login</a>
</p>
</>
)}
</p>
);
};
Login.js
import React, { useState, useEffect } from "react";
export default (props) => {
const [isLogged, setIsLogged] = useState(false);
const [token, setToken] = useState();
const [email, setEmail] = useState();
const [user, setUser] = useState({});
const authChannel = new BroadcastChannel("auth");
const [input, setInput] = useState({
email: "superadmin@a.com",
password: "quantum"
});
useEffect(() => {
authChannel.onmessage = function (e) {
if (e.data.action === "logout") {
setIsLogged(false);
setToken();
setUser({});
}
};
}, [authChannel]);
useEffect(() => {
setToken(sessionStorage.getItem("token"));
setEmail(sessionStorage.getItem("email"));
setIsLogged(sessionStorage.getItem("token") ? true : false);
}, []);
const handleLogin = () => {
// handle login here...
authChannel.postMessage({
action: "login",
target: "*",
data: {
user: { email: "a@a.com" },
token: "kjdhlfjkgdjgdlfghjldhjgh76lgj"
}
});
setIsLogged(true);
};
const handleInputChange = (e, source) => {
setInput({ ...input, [source]: e.target.value });
};
return (
<div>
{!isLogged && (
<>
<div>
<label>Email</label>
<input
type="text"
value={input.email || ""}
onChange={(e) => handleInputChange(e, "email")}
/>
</div>
<div className="flex">
<label>Password</label>
<input
type="password"
value={input.password || ""}
onChange={(e) => handleInputChange(e, "password")}
/>
</div>
<button onClick={() => handleLogin()}>Login</button>
</>
)}
{isLogged && <h1>You are logged now</h1>}
</div>
);
};
Please do let me know what can be the reason for this.