React Native 在加载时多次订阅 websocket

React Native subscribes multiple times to websocket on load

提问人:Leon 提问时间:8/23/2023 更新时间:8/23/2023 访问量:39

问:

我是react native的新手,我正在尝试编写一个小应用程序,该应用程序连接到由Rails ActionCable提供支持的websocket,发送一条消息,然后当我单击“断开连接”时,它会关闭连接并取消订阅频道。

这是我在 react native 端的代码:

import React, { useState, useEffect, useCallback } from 'react';
import { View, Text } from 'react-native';
import { Button } from 'react-native-paper';
import { ActionCable, Cable } from '@kesha-antonov/react-native-action-cable';
import UUID from 'react-native-uuid';

const actionCable = ActionCable.createConsumer('wss://blabla.ngrok-free.app/cable');
const cable = new Cable({}) 

const App: React.FC = () => {

  //const actionCable = ActionCable.createConsumer('wss://blabla.ngrok-free.app/cable');
  //const cable = new Cable({}) 

  // const channel = cable.setChannel(
  //   `wire_channel_${identifier}`, // channel name to which we will pass data from Rails app with `stream_from`
  //   actionCable.subscriptions.create({
  //     channel: 'WireChannel', // from Rails app app/channels/chat_channel.rb
  //   })
  // )

  const [isWebsocketConnected, setIsWebsocketConnected] = useState(false);
  const [dchannel, setDchannel] = useState();

  const identifier = UUID.v4();
  console.log(identifier);

  const onNewMessage = useCallback(message => {
  }, [])

  const handleReceived = useCallback(({ type, message }) => {
    console.log(type);
    console.log(message);
    console.log("triggered")
  }, [])

  const handleConnected = useCallback(() => {
    setDchannel(cable.setChannel(
      `wire_channel_${identifier}`, // channel name to which we will pass data from Rails app with `stream_from`
      actionCable.subscriptions.create({
        channel: 'WireChannel', // from Rails app app/channels/chat_channel.rb
      })
    ))  
    setIsWebsocketConnected(true)
  }, [])

  const handleDisconnected = useCallback(() => {
    removeChannel()
    setIsWebsocketConnected(false)
  }, [])

  const handleSendMessage = useCallback(() => {
    const channelName = getChannelName(identifier)
    const channel = cable.channel(channelName)
    dchannel.perform('speak', { message: 'Hey', identifier: identifier })
  })

  const getChannelName = (identifier) => {
    return `wire_channel_${identifier}`
  };


  const removeChannel = useCallback(() => {
    const channelName = getChannelName(identifier)
    console.log("getChannelName: "+channelName);

    const channel = cable.channel(channelName)
    console.log(channel);
    if (!channel)
      return

    channel
      .removeListener( 'received', handleReceived )
      .removeListener( 'connected', handleConnected )
      .removeListener( 'disconnected', handleDisconnected )
    channel.unsubscribe()
    console.log(cable.channels)
    delete( cable.channels[channelName] )
    console.log(cable.channels)
  }, [])

  useEffect(() => {
    // channel.on('received', handleReceived);
    // channel.on('connected', handleConnected);
    // channel.on('disconnected', handleDisconnected);

    return () => {
      if(dchannel){
        dchannel.unsubscribe();
      }
    };
  }, []); 

  return (
    <View style={{ flex: 1 }}>
      <View style={{ padding: 20, backgroundColor: '#f0f0f0', alignItems: 'center' }}>
        <Text style={{ fontSize: 24 }}>Your Logo Here</Text>
      </View>
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Button
          mode="contained"
          onPress={handleConnected}
          color="#00C853" // Green color for "Connect" button
          disabled={isWebsocketConnected}
        >
          Connect WebSocket
        </Button>
        <Button
          mode="contained"
          onPress={handleDisconnected}
          color="#FF1744" // Red color for "Disconnect" button
          disabled={!isWebsocketConnected}
        >
          Disconnect WebSocket
        </Button>
        <Button
          mode="contained"
          onPress={handleSendMessage}
          disabled={!isWebsocketConnected}
        >
          Send Message
        </Button>
        <Text>
          WebSocket Status: {isWebsocketConnected ? 'Connected' : 'Disconnected'}
        </Text>
        {/*<Text>Counter: {counter}</Text>
        <View style={{ marginTop: 20 }}>
          <Text>Messages from Server:</Text>
          {messages.map((message, index) => (
            <Text key={index}>{message}</Text>
          ))}
        </View>*/}
      </View>
    </View>
  );
};

export default App;

我遇到的问题是,当应用程序加载时,我看到在服务器端创建了很多订阅,当我单击发送消息时,服务器会广播多条消息(每个创建的订阅 1 条)。我只想建立 1 个订阅,并且只有在我单击“连接 Websocket”按钮时才应该建立订阅。

我怎样才能在上面的代码中实现这一点。我已经尝试了多种方法。

React-Native 操作电缆 Ruby-on-Rails-7

评论


答:

1赞 Lalit kumar 8/23/2023 #1

请删除代码中的 usecallback 钩子并检查输出。usecallback 并不适用于每个函数。请检查

React 中的 useCallback 是什么,何时使用它?

用于有效使用 usecallback 钩子。

评论

1赞 Leon 8/25/2023
谢谢,遵循这个之后,不仅能够理解回调和其他钩子,而且还能够理解钩子上的参数数组。谢谢。