反应 BroadcastChannel 出错 API
React Getting error with BroadcastChannel API
我正在使用 sessionStorage 来保存授权信息,并且需要将此信息复制到其他打开的选项卡。我创建了一个 codesandbox 来重现问题。我没有在这个 post 中包含代码,因为它太长了。
当仪表板link在另一个window中打开时,由于弹出错误而无法呈现。
编辑:
我在下面包含了所有必要的代码。
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>
);
};
请告诉我这可能是什么原因。
您收到一个错误,因为您在此处发送未定义的数据:
Home.js
authChannel.postMessage({
action: "login",
target: e.data.source,
data: { user: user, token: token } //--> user and token are undefined
});
我还建议您更改此行:
const authChannel = new BroadcastChannel("auth");
因为每次渲染组件时,都会创建一个 BroadcastChannel
的新实例。为避免这种情况,您需要将 BroadcastChannel
实例存储在 useRef
:
中
const authChannelRef = useRef(new BroadcastChannel("auth"));
const authChannel = authChannelRef.current;
我正在使用 sessionStorage 来保存授权信息,并且需要将此信息复制到其他打开的选项卡。我创建了一个 codesandbox 来重现问题。我没有在这个 post 中包含代码,因为它太长了。
当仪表板link在另一个window中打开时,由于弹出错误而无法呈现。
编辑: 我在下面包含了所有必要的代码。
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>
);
};
请告诉我这可能是什么原因。
您收到一个错误,因为您在此处发送未定义的数据:
Home.js
authChannel.postMessage({
action: "login",
target: e.data.source,
data: { user: user, token: token } //--> user and token are undefined
});
我还建议您更改此行:
const authChannel = new BroadcastChannel("auth");
因为每次渲染组件时,都会创建一个 BroadcastChannel
的新实例。为避免这种情况,您需要将 BroadcastChannel
实例存储在 useRef
:
const authChannelRef = useRef(new BroadcastChannel("auth"));
const authChannel = authChannelRef.current;