简体   繁体   English

使用 BroadcastChannel API 反应出现错误

[英]React Getting error with BroadcastChannel API

I am using sessionStorage to keep the auth information and need to replicate this information to other tabs being opened.我正在使用 sessionStorage 来保留身份验证信息,并且需要将此信息复制到正在打开的其他选项卡。 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.在另一个 window 中打开 Dashboard 链接时,由于弹出错误而无法渲染。

EDIT: I have included all the necessary codes below.编辑:我在下面包含了所有必要的代码。

App.js应用程序.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仪表板.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主页.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登录.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.请让我知道这可能是什么原因。

You are getting an error because you are sending undefined data here:您收到错误是因为您在此处发送未定义的数据:

Home.js主页.js

authChannel.postMessage({
  action: "login",
  target: e.data.source,
  data: { user: user, token: token } //--> user and token are undefined
});

Also I recommend you to change this line:我还建议您更改此行:

 const authChannel = new BroadcastChannel("auth");

Because every time the component is rendered, a new instance of BroadcastChannel is created.因为每次渲染组件时,都会创建一个新的BroadcastChannel实例。 To avoid this you need to store the BroadcastChannel instance in useRef :为避免这种情况,您需要将BroadcastChannel实例存储在useRef中:

  const authChannelRef = useRef(new BroadcastChannel("auth"));
  const authChannel = authChannelRef.current;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Postman 中的 API 工作正常,但在本机反应中出现 422 错误 - API in Postman works fine but getting 422 error in react native 如何使用BroadcastChannel API或Safari 10+中的类似功能? - How can I use the BroadcastChannel API or something similar in Safari 10+? 通过 React 中的回调函数获取 API - Getting the API by the callback function in React 让 API 在反应中呈现的问题 - Issue getting API to render in react 在React中获取解析错误 - Getting Parse Error in React 我在 NodeJS 上没有收到任何 CORS 错误(适用于 Node),但在获取 API 时在 React 和 Javascript 上收到错误 - I am not getting any CORS error on NodeJS (Works Fine with Node) but I am getting the error on React and Javascript while fetching API 使用 openweather API “TypeError: Cannot read properties of undefined (reading 'temp')”做出反应时出错 - Getting an error in react using openweather API "TypeError: Cannot read properties of undefined (reading 'temp')" 尝试使用反应钩子显示来自 API 的数据时出现类型错误 - Getting a type error when try to display data from API using react hooks BroadcastChannel / MessageEvent时间戳? - BroadcastChannel / MessageEvent timestamp? BroadcastChannel 有时不监听 useEffect - BroadcastChannel sometime not listening at useEffect
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM