1

我正在使用 sessionStorage 来保留身份验证信息,并且需要将此信息复制到正在打开的其他选项卡。我创建了一个代码框来重新创建问题。我没有在这篇文章中包含代码,因为它很长。

在另一个窗口中打开 Dashboard 链接时,由于弹出错误,它没有呈现。

编辑: 我在下面包含了所有必要的代码。

应用程序.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>
    </>
  );
}

仪表板.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>}
    </>
  );
};

主页.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>
  );
};

登录.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>
  );
};

请让我知道这可能是什么原因。

4

1 回答 1

3

您收到错误消息,因为您在此处发送未定义的数据:

主页.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;
于 2021-01-24T13:02:33.430 回答