【问题标题】:React Getting error with BroadcastChannel API使用 BroadcastChannel API 反应获取错误
【发布时间】:2021-01-23 17:54:58
【问题描述】:

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

Dashboard 链接在其他窗口打开时,由于弹出错误,未呈现。

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

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>
  );
};

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

【问题讨论】:

  • 我建议您添加部分代码和您遇到的错误。
  • 如果您在 safari 中运行代码,BroadcastChannel 不起作用,您可以在这里找到一些答案stackoverflow.com/questions/57700474/…
  • @lissettdm 我正在使用 chrome,如果我可以让它在 Chrome 中工作就可以了。

标签: javascript reactjs react-router-dom broadcast-channel


【解决方案1】:

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

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;

【讨论】:

  • 感谢您的回复,我会按照您说的尝试更新。
猜你喜欢
  • 2022-07-07
  • 1970-01-01
  • 2018-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-14
  • 2018-06-10
  • 2019-09-01
相关资源
最近更新 更多