Reactjs:如何在组件之间共享websocket

17
我刚接触React,对组件结构以及如何在它们之间共享WebSocket存在一些问题。
应用程序包括分类和产品。初始数据加载将使用Ajax请求完成,并使用WebSocket来保持数据更新。
我的组件层次结构如下:
- CategoriesList
- Category
- ProductsList
- Product
CategoriesList保存分类的状态,而ProductsList保存类别内产品的状态。
因此,我想在CategoriesList和ProductsList之间共享同一个WebSocket,但侦听不同的WebSocket事件:category:updated和product:updated。
如何在组件之间共享WebSocket,并在哪里初始化它是正确的位置?
由于每个Category都有一个ProductsList,这是否意味着products:updated事件会多次触发(每个类别一次)?我认为从性能角度来看这并不是好事情。

我将使用推文来描述React对你的实现有多关注 https://twitter.com/AdamRackis/status/707004963776430080 我会通过上下文(也许是?!)传递套接字连接实例,这将允许组件监听更改。请随意使用您感到舒适的任何内容。React不会限制您。 - Andreyco
是的,您可以通过props传递它来共享它,或者使用像Flux这样的架构,在存储器中存在套接字,您可以从任何地方访问。在componentDidMount中侦听事件,并在componentWillUnmount中取消侦听事件。您是否使用任何Web套接字库,例如Socket.IO? - Aaron Beall
@Aaron 我正在使用Pusher.com提供的库。 - Fernando
6个回答

22

另一种共享相同实例的方法是简单地创建一个新文件,如下所示:socketConfig.js

import openSocket from 'socket.io-client';

const socket = openSocket("http://localhost:6600");

export default socket;

你可以在任何想要的文件中使用它,只需要导入它。

import socket from "../socketConfig";

这对我来说是有效的,因为我在两个不相互依赖的组件中使用它。


2
这是有帮助的答案!一个扩展问题:如果URL本身是动态的,并且取决于组件将值加载到其中,您会如何处理? openSocket(dynamicUrlHere) - iWillGetBetter
1
你如何在React和JS中使用它?例如,我有一个用于Phaser游戏的JS文件,它使用React。 - user3768258

10
我建议在CategoriesList中初始化您的套接字连接,然后将连接作为道具传递给子组件。当连接被传递时,您应该能够在子组件中根据需要使用它来监听特定事件。
这里有一个在github上使用react和socket.io的示例应用程序。套接字在父组件中进行初始化,然后传递下去。https://github.com/raineroviir/react-redux-socketio-chat/blob/master/src/common/containers/ChatContainer.js 在第9行初始化连接,然后在第23行将其作为道具传递。稍后在子组件中使用连接来接收和发射事件。例如:https://github.com/raineroviir/react-redux-socketio-chat/blob/master/src/common/components/Chat.js

5
渲染会在服务器端创建多个连接。这不是最优的做法。 - JKhan

1
如果您正在使用Redux Store,则将socket存储在Redux Store中,然后您可以像访问其他存储变量/状态一样从任何组件中访问它。
组件A(在组件A中定义Socket):

//...
const dispatch = useDispatch();

useEffect(() => {
  const socket = io("http://localhost:8000");
  socket.on("connect", () => {
    console.log("Connected to Socket");
    dispatch({
      type: "INIT_SOCKET",
      socket: socket
    });
  });
}, [...]);

组件:B(在另一个组件中使用Socket)

//...
const socket = useSelector(state => state.socket);

useEffect(() => {
  if (socket) {
    socket.on("msg", (data) => {
      console.log(data);
    });
  }
}, [socket]);


0

创建socket.config.js文件,为您的Websockets添加打开连接。

export const WebSocket1 = new WebSocket('ws://YOUR websocketurl');
export const WebSocket2 = new WebSocket('ws://YOUR anotherwebsocketurl');

导入到您的任何组件中

import  {WebSocket1, WebSocket2}from '../../../utils/socket.config';

在 UseEffect 钩子内部利用 WebSocket

 useEffect(() => {
WebSocket1.onopen = () => {
    WebSocket1.send(JSON.stringify(someData));
};

    WebSocket1.onmessage = (event: any) => {

      console.log(JSON.parse(event.data));
        
        
    }

    WebSocket1.onerror = error => {
        console.log(`WebSocket error: ${error}`);
    };

    WebSocket1.onclose = () => {
        console.log("disconnected");
    }
}, []);

0

只需在组件外部声明套接字,就像这样...

import SocketIOClient from 'socket.io-client';   
const socket=SocketIOClient('http://localhost:3000/chat')

function App() {
    //use socket here ...

    return (
        <div> </div>);
}

-2

请查看react-cent 您可以编写自己的Provider(CentProvider.js)来包装您的组件并通过上下文提供客户端。此外,编写Higher-Order Component(CentComponent.js),以便通过this.props.<client>使其可用


这个答案(针对一个旧问题)依赖于指向第三方包的链接,该链接可能并不总是存在。今后,请在您的文本中包含针对 OP 的具体信息来回答问题。 - kwishnu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接