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: "[email protected]",
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: "[email protected]" },
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.
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: "[email protected]",
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: "[email protected]" },
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.
Share Improve this question edited Jan 24, 2021 at 3:33 Lakmal Premaratne asked Jan 23, 2021 at 17:54 Lakmal PremaratneLakmal Premaratne 1,2297 gold badges19 silver badges36 bronze badges 3- I remend you to add part of your code and the error you are getting. – lissettdm Commented Jan 23, 2021 at 19:38
- 1 If your are running your code in safari, BroadcastChannel doesn't work, here you can find some answer stackoverflow./questions/57700474/… – lissettdm Commented Jan 23, 2021 at 19:40
- @lissettdm I am using chrome and it is fine if I can get it working in Chrome. – Lakmal Premaratne Commented Jan 24, 2021 at 3:47
1 Answer
Reset to default 5You are getting an error because you are sending undefined data here:
Home.js
authChannel.postMessage({
action: "login",
target: e.data.source,
data: { user: user, token: token } //--> user and token are undefined
});
Also I remend you to change this line:
const authChannel = new BroadcastChannel("auth");
Because every time the ponent is rendered, a new instance of BroadcastChannel
is created. To avoid this you need to store the BroadcastChannel
instance in useRef
:
const authChannelRef = useRef(new BroadcastChannel("auth"));
const authChannel = authChannelRef.current;