是否可以将 React Native 与 socket.io 结合起来

Is it possible to combine React Native with socket.io

我正在使用 Phonegap + React.js 和 Socket.io 开发一个应用程序。然而,随后 React-Native 发布了,原生的感觉非常棒。

我尝试让 socket.io-client 与 React Native 一起工作,但不幸的是没有太大的成功。我做了一些研究,我得到了与本期中描述的完全相同的错误:https://github.com/facebook/react-native/issues/375

问题上的评论说尝试使用 fetch API 来获取 JS 模块,但我认为我这样做是错误的:

var socketScript;    
fetch('https://cdn.socket.io/socket.io-1.2.0.js')
    .then(function(response) {
        socketScript = response._bodyText;
    }).done(function() {
        var socket = socketScript.io();
    });

这个 returns 一个 undefined 不是函数

有没有办法让 socket.io-client 与 React Native 一起工作?还是我看错了?也许还有其他更适合的解决方案?

编辑 2016 年 2 月:React Native 现在支持 Web 套接字,因此其中一些建议无效。

恐怕您误解了 Github 问题。其中,aackerman 说:

For this specific case you'll likely want to use the fetch API which is provided by the environment.

没有说你应该使用fetchAPI来抓取远程JS模块。他的建议是使用 fetch API 代替内置的 Node.JS 请求模块,后者在 React Native 中不可用。

让我们看看你的代码:

socketScript = response._bodyText;
var socket = socketScript.io();

想一想 - socketScript 不是 JavaScript 对象,它是一个字符串 - 那么你如何调用它的 io 方法?

你真正需要做的是在使用它之前解析 _bodyText(在浏览器中你可以使用 eval),但是你仍然会遇到 React Native 的问题有一个用于 XHR 和 fetch API 的 polyfill,它还没有一个用于 WebSocket API。除非我弄错了,这意味着你被卡住了。

我建议打开一个 Github 问题来请求 WebSocket API polyfill 并询问社区的想法。有人可能有解决方法。

缺少 WebSocket API 的 polyfill,您可以创建一个使用网络套接字的本机模块,并使用 eventDispatcher 将事件发送到 Javascript。

在 Javascript 端,您可以使用 DeviceEventEmitter.addListener 订阅这些事件。

有关使用本机模块的详细信息,请参阅 react-native doc on the topic

对于那些像我一样在寻找如何将 socket.io 与 React Native 集成的问题上跌跌撞撞的人。

由于 React Native 支持 websockets 的时间很短,您现在可以使用 Socket.io 非常轻松地设置 web sockets。您所要做的就是以下

  1. npm 安装socket.io-客户端
  2. 首先导入 react-native
  3. 分配window.navigator.userAgent = 'react-native';
  4. 导入套接字.io-client/socket.io
  5. 在你的构造函数中赋值 this.socket = io('localhost:3001', {jsonp: false});

所以在 npm 安装 socket.io-client:

之后它应该看起来像这样
import React from 'react-native';

// ... [other imports]

import './UserAgent';

import io from 'socket.io-client/socket.io';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.socket = io('localhost:3001', {jsonp: false});
  }

  // now you can use sockets with this.socket.io(...)
  // or any other functionality within socket.io!

  ...
}

然后在 'UserAgent.js':

window.navigator.userAgent = 'react-native';

注意:因为 ES6 模块导入被提升,我们不能在与 react-native 和 socket.io 导入相同的文件中进行 userAgent 分配,因此是单独的模块。

编辑:

上述解决方案应该可行,但在这种情况下它不会尝试创建单独的 socketConfig.js 文件。在那里导入任何需要的东西,包括 const io = require('socket.io-client/socket.io'); 并且在需要 socket.io-client 之前有 window.navigator.userAgent = 'react-native';。然后你可以在那里连接你的套接字并将所有听众放在一个地方。然后可以将动作或函数导入到配置文件中,并在侦听器接收到数据时执行。

现在,如果您想在您的 RN 应用程序中使用 socket.io,您必须使用此代码:

if (!window.location) {
    // App is running in simulator
    window.navigator.userAgent = 'ReactNative';
}

// This must be below your `window.navigator` hack above
const io = require('socket.io-client/socket.io');
const socket = io('http://chat.feathersjs.com', {
  transports: ['websocket'] // you need to explicitly tell it to use websockets
});

socket.on('connect', () => {
  console.log('connected!');
});

非常感谢Eric Kryski

终于找到了。

客户

import { io } from "socket.io-client/build/index"
io("ws://<LOCAL HOME NETWORK IP>:<PORT ON SERVER>")

服务器

import express from "express"
import http from "http"
import * as SocketIO from "socket.io"

const app = express()
const server = new http.Server(app)
const io = new SocketIO.Server(server)
const port = 8000
io.on("connection", socket => {
   console.log("CONNECTIONS")
}
import { io } from 'socket.io-client'
const socket = io(`${SOCKET_URL}:${SOCKET_PORT}`)

重要! SOCKET_URL 应该是您的本地 IP 地址,而不是 localhost127.0.0.1

检查您的本地 IP:
Mac / Linux: 运行 ifconfig 在终端
Windows: 运行 ipconfig --all 在 shell

应该是这样的:const socket = io('http://10.0.1.6:3000', {transports: ['websocket']})

可能是这将通过错误

import io from "socket.io-client/socket.io"

然后在下面添加一行....

import io from "socket.io-client/dist/socket.io";

然后在 componenDidMount 或 useEffect 函数中添加 line.Never 在 class 组件的构造函数下使用它。

 var socket = io("https://localhost.com:3000", { jsonp: false });
        // client-side
        socket.on("chat_message", (msg) => {
            console.log(msg);
        });

尽管您可以使用 socket.io-client 库,但社区抱怨大多数版本存在兼容性问题(我确实遇到过一些)。它有效,但现在我不敢升级 lib,因为我需要验证下一个版本与我的服务器版本和 react-native 版本的兼容性!

好像很多人都怀念react's own implementation of Websockets!我真的建议您使用它而不是 socket.io-client。用法很相似:

var ws = new WebSocket('ws://host.com/path');
ws.onopen = () => {  // connection opened  ws.send('something'); // send a message};
ws.onmessage = (e) => {  // a message was received  console.log(e.data);};
ws.onerror = (e) => {  // an error occurred  console.log(e.message);};
ws.onclose = (e) => {  // connection closed  console.log(e.code, e.reason);};

2022 年答案

在 2022 年,您可以轻松地使用最新版本的套接字。io-client 和 React Native。

npm install socket.io-client

import io from 'socket.io-client';

目前还没有一个很好的基于 hook 的 socketIO 库,我已经能够使用 RN,但是根据您的需要推出您自己的自定义 hook 非常简单。浏览器

function useWebsocket(url) {
    const [connected, setConnected] = useState(false);
    const [socket, setSocket] = useState(null);
    useEffect(()=>{
        const newSocket = io(url);
        newSocket.on('connect', ()=>setConnected(true));
        newSocket.on('disconnect', ()=>setConnected(false));
        setSocket(newSocket);
    }, [])
    return {
        connected,
        socket,
    }
}

像这样的东西可以让你开始。这将为调用挂钩的每个组件打开一个套接字,如果您只需要一个组件和一个连接,它可以很好地工作。跨组件共享连接有点麻烦,但还不错。

connected 状态对于让您的用户了解连接状态和类似内容非常有用。

但是,是的,关键是您可以安装它并在您的组件中使用它。不要在你的功能组件中使用它