How to Get Socket.io to work with React-Native

After a frustrating couple of days trying to get socket.io to connect to a web socket on my Node/Express server for my project HereHere (place based chat app – please check it out if interested), I finally found out how to make it play nice with React-Native (v0.57).  After reading through numerous posts, GitHub issue threads and blog articles, I thought it would be nice to have one place where you can go to get socket.io working with your React-Native project, so this is just a quick post on how to get it set up and working.

Key points:

  • You need to use socket.io-client on the react-native client side of things
  • The latest version of socket.io-client 2.2.0 does not work with React-Native currently apparently, so you need to install and use version 2.1.1
  • In development, the connection URL on the client side may need to be set to one of three possible values: http://localhost:<serverPort>, http://127.0.0.1:<serverPort>, http://<your IP assigned by your router>:<serverPort>, or if using an Android emulator (I did not need to do this, but it was recommended on a Stack Overflow post, so try it if all else fails) http://10.0.2.2:<serverPort>
  • In production, the connection URL on the client side needs to be pointing to the URL where your server is hosted that handles websocket connections: https://yourserverurl.com
  • Note: I am using Expo to bootstrap my React-Native project.
  • I am also using a Node.js server built with Express on the back end.

Steps:

    1. Install socket.io-client v2.1.1 in your react-native client side project.
      $ npm install [email protected]
    2. In your main App.js file or wherever you would rather initialize socket.io, import the library:
      import socketIO from 'socket.io-client';
    3. Connect to a Web Socket connection to your server by assigning a const to a call to the imported library function and pass in the url to your server (see the possible values in key points above!!) .  Also, pass in some config params, the most important of which is the `transports` key set to `websocket`.
    4. Connect the socket with .connect() and and add a listener to confirm the connection with a console.log.
      Note: initialize socketIO in componentDidMount() in your main App.js file for your React-Native app.  You could extract the code to a module file and call it ‘startSocketIO.js’ to make things cleaner in App.js.

In App.js (your main app component on the client):

import React from 'react';
import { Platform, StatusBar, StyleSheet, View } from 'react-native';
import { startSocketIO } from './services/socketIO';
// ...any other imports needed

export default class App extends React.Component {
  state= {
    isLoadingComplete:false,
  };
componentDidMount() { 
  const socket = socketIO('http://192.168.0.8:5000', {      
  transports: ['websocket'], jsonp: false });   
  socket.connect(); 
  socket.on('connect', () => { 
    console.log('connected to socket server'); 
  }); 
}

// In this case, note that I used the IP address for my machine assigned by the router (in Network Connection details).  This got it working in my development environment.

For further clarity here is an example of some of the code in my Socket IO module where I initialize and use the library.  I export the module to be used in componentDidMount() in my App.js component (top level App component):

 

import socketIO from 'socket.io-client';
...other imports like config file containing Server Url, any secrets, and actions...
// Initialize Socket IO:
const socket = socketIO(config.SERVER_URL, {
  transports: ['websocket'],
  jsonp: false
});

// export the function to connect and use socket IO:
export const startSocketIO = (store) => {
  socket.connect();
  
  socket.on('connect', () => {
    const { userId } = store.getState().user;
  
  socket.on('disconnect', () => {
    console.log('connection to server lost.');
  });
  
  socket.on('newMessage', (message) => {
    store.dispatch(storePublicMessages([ message ]));
  });
};


// In App.js:
import startSocketIO from ...

export default class App extends React.Component {
  componentDidMount() {
    startSocketIO(store);
  }

  render() {
      return (
        <Provider store={store}>
          <View style={styles.container}>  
            <AppNavigator />
          </View>
        </Provider>
      );
    }
  }
}

SETTING UP SOCKETIO IN PRODUCTION:

In order to get it going in Production, you need to pass in the domain URL pointing to where you are hosting your server.  In my case I hosted a Node/Express server on Heroku:

In App.js inside componentDidMount():

const socket = socketIO('https://myserver.onheroku.com', {
  transports: ['websocket'], 
  jsonp: false 
}); 
socket.connect(); 
socket.on('connect', () => { 
  console.log('connected to socket server'); 
});

This was mainly about getting things setup to work on the client side with React-Native, but just for completeness sake, here is a quick snippet of my server.js file which sets up an Express server and socket.io.  Note that on the server side I am using the socket.io library (the latest version) and not socket.io-client.  Also note, that you need to use the builtin https Node module to create a server which you pass the express app into, and then pass that server to socketIO.

Example Main Server file in back end code of the project:

const http = require('http');
const express = require('express');
const socketIO = require('socket.io');
const mongoose = require('mongoose');
const keys = require('./config/keys');
require('./models/Message');

const PORT = process.env.PORT || 5000;
mongoose.connect(keys.mongoURI);

const app = express();
const server = http.createServer(app);

const io = socketIO(server);
io.on('connection', socket => {
  console.log('client connected on websocket');
});

server.listen(PORT, () => {
  console.log('server started and listening on port ' + PORT);
});

Hopefully, this will save you some headache and time pouring through Stack Overflow and posts trying to figure out why your socket IO connection is not working in React-Native.  If you have any questions, comments or suggestions feel free to post them in the comments section and I’ll help with whatever I can.