如何在 React Native 中为 SignalR 创建单例模式

How to create a singleton pattern for SignalR in React Native

这个 React 本机项目使用 SignalR 从 .NET 核心服务器获取实时更新。我目前有一个处理 SignalR 集线器连接的功能组件,它是在 App.js 中导入的,但在这样做时,应用程序会在某些重新呈现上创建新连接。使用@microsoft/signalr时如何确保存在单例模式?

这是当前代码:

const SignalR = () => {
  const [connection, setConnection] = useState(null);

  if (!connection) {
    const conn = new signalR.HubConnectionBuilder()
      .withUrl(`${url.api}/latest`, {
        accessTokenFactory: async () => {
          const creds = JSON.parse(await getCredentials());
          if (!creds) {
            return null;
          }
          const token = await B2CAuthentication.getInstance().assureToken(
            creds,
          );
          return token;
        },
      })
      .configureLogging(signalR.LogLevel.Warning)
      .withAutomaticReconnect()
      .build();

    conn
      .start()
      .then(async () => {
        request({url.api}).then(async () => {
          await console.log('Connected to SignalR');
        });
      })
      .catch(async () => {
        await console.log('Error starting SignalR');
      });

    setConnection(conn);

  return <></>;
};

export default SignalR;

你使用一个函数组件来做到这一点,只要 App 组件更新,SignalR 组件就会reRun.I认为你可以做到这一点,只需使用一个没有依赖的 useEffect。

//in App.js
useEffect(()=>{
  const conn = new signalR.HubConnectionBuilder()
  .withUrl(`${url.api}/latest`, {
    accessTokenFactory: async () => {
      const creds = JSON.parse(await getCredentials());
      if (!creds) {
        return null;
      }
      const token = await B2CAuthentication.getInstance().assureToken(
        creds,
      );
      return token;
    },
  })
  .configureLogging(signalR.LogLevel.Warning)
  .withAutomaticReconnect()
  .build();

  const restart = () => {
    if (!conn) {
      return;
    }
    if (conn.state !== signalR.HubConnectionState.Disconnected) {
      return;
    }
    try {
      await conn.start();
    } catch (err) {
      setTimeout(restart, 5000);
    }
  }

  conn.onclose(() => {
    console.log('Disconnected. Restarting.');
    restart();
  });


  conn.start()
  .then(async () => {
    request({url.api}).then(async () => {
      await console.log('Connected to SignalR');
    });
  })
  .catch(async () => {
    await console.log('Error starting SignalR');
  });

},[])