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.

25 thoughts on “How to Get Socket.io to work with React-Native”

  1. Hey! Thank you for the blog post.
    I was wondering if you knew how to get socket.io to work (with express) on the production scale, aka how to deploy it with a functional Node server? I found janeasystems solution (NodeJS for mobile), but it seems like it only works with separate iOS and Android builds.
    Thanks!

    1. Hi Aurélie, I have deployed socket io on a Production Node/Express server and the part that seemed most important to set it up was to use the included Node http module and pass your express app into it’s Server method. You then need to use that to initialize SocketIO (pass server into the socketIO function)

      Here is an example of my main server index.js file:

      const express = require('express');
      const path = require('path');
      const socketIO = require('socket.io');

      const app = express();
      app.set('port', PORT);
      const server = require('http').Server(app);
      const io = socketIO(server);

      io.on('connection', socket => {
      ...socketIO listeners and emitters...
      }

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

      Let me know if this answers your question or if you need anything else. Thanks for visiting the site.
      -Brent

      1. Hey, thank you for taking the time! I appreciate it.
        I’ve done it and it’s working locally so far, but I try to connect my client to the server side on Heroku, I get a “there was a problem sending log messages to your development environment” error message on my iOS simulator. There’s probably something silly I’ve forgotten.

      2. I think I got my problem.
        I pasted your code:

        const socket = socketIO(‘http://192.168.0.8:5000’, {
        transports: [‘websocket’],
        jsonp: false
        });
        socket.connect();
        socket.on(‘connect’, () => {
        console.log(‘connected to socket server’);
        });

        And replaced your IP address by various websocket adresses (“ws://sample.testable.io/streaming/websocket” for example) but I didn’t get any console log.
        Yet socket.io worked perfectly on local, and I got logs from my emits.

        If you got any idea as to why, I’m open to hear so! Thank you again.

  2. Hey Aurélie,

    I am hosting my Node server on Heroku and I pass in the URL to socketIO. Try passing in the root http/https protocol URL(i.e. (“https://yourdomain.com”)) where your server is hosted instead of a websocket protocol URL and see if that does the trick. The idea is that you’re going to open a connection pointing to wherever your Node Server is hosted which manages the socket connection. Let me know if this helps and how things go.

    See the updated blog post with notes on getting things set up for production and let me know if you still have problems and I’ll try to help.

    -Brent

    1. Hi Brent, I’m getting the [Error: websocket error] after using your code, and what IP address should be used? I used Ipconfig to view my machine’s IP address but didnt get IP address under “Ethernet adapter Ethernet” although Im connected on the same Wifi on my phone as the machine. I had been using adb reverse to make requests to my REST apis via my android phone but still seeing this websocket error.

      Awaiting for your response. Thanks in advance.
      – Rachna

      1. Hi Rachna, I’ll try to help as best I can. If you’re developing locally, then you need to point your react-native app to call the IP address assigned to your computer in your network settings (I’m using windows, so I open the network settings and ethernet settings to see what my IP is). Example: `http://192.168.0.15:5000`. The port should be what you set for your development server to use in dev. For production, you need to point your app to your host domain where your server is. `https://my-server-host.com`
        Hope this helps and thanks for visiting my site.
        -Brent

    1. Hey Fabiano,
      I’m glad my blog post helped you out. Using version 2.1.1 over the latest version was a gotcha I eventually found out after some frustration in addition to the other points, so I hope it saved you some time and headache. Thanks for visiting the site!
      -Brent

  3. Hi, i have some questions, i developp with react native but i use cakephp s backend api, which ip i will use for server ip its my web server ip or what im confuse here. Thks for your answer

    1. Hi Carlos,

      I have not used cakephp so I won’t be able to offer much advice in regards to that, but on the client/app side during development you probably want to use your local IP address, and when you deploy online, use the web server domain. You can try to set and check an environment variable for production or development which will point to the local ip or web server domain, or just make sure to switch it manually before deploying to point to your web server domain where your server is hosted. Sorry I can’t speak to cakePHP at the moment, but I hope this helps some. Thanks for the question.
      -Brent

    1. Hi John, You create a separate keys.js file to store your secrets. These would be things like your database URI which contains your password or any other API secret keys or values that you do not want to check into a public version control repository (i.e. on GitHub) where other people could see it.

      So you could create keys.js and do something like:

      module.exports = {
      DATABASE_URI: 'mydb:myusername:mypassword...'
      SECRET_API_KEY: 'lsdlkjfsldkfjklsdfj'
      }

      Then in your source code which is checked in to a version control system (i.e. what you commit with git to GitHub, etc.) you require the keys file and use the property names instead of the actual values (keys.DATABASE_URI). This keeps sensitive code private so that the public does not see your passwords or other keys needed in your code on wherever your public repo is.

      Don’t forget to add keys.js in your .gitignore file so that your check ins to git will not include it. If you make this mistake then usually the VCS will warn you after you’ve pushed to the repo and you’ll need to change your keys and passwords and remove your files from the repo history (this can be cumbersome..you could alternatively delete the repo and start a new one).

      Another way of storing secrets is using a .env file and a package like node-env so that you can access the values on process.env.YOUR_SECRET etc. If you’re deploying to Heroku, then you’ll need to set these keys in the dashboard for your app (look up set environment variables for Heroku on Google).

      Hope this helps and thanks for reading the post and visiting the site. -Brent

  4. Hi Brent,

    Just wanted to say thank you so much for the post. it was very helpful, saved me alot of time and worked like a charm. I was trying the socket on the Android emulator and your post was the only one out there which mentioned the 10.0.2.2 address

    Cheers !

    1. Hi Amir, Glad it helped – had to read through a lot of stack overflow posts and articles to figure out how to get it working, so I wanted to save others the time. Thanks for visiting the site.
      -Brent

  5. Hello, thanks for all! I did the steps of your tutorial, but it seems that I never connect with my server. The callback of socket.on is never triggered (‘connect’ …

    1. Hi Lucas,

      Getting socketIO setup was tricky and my post addresses some of the common problems I saw others run into and that I ran into myself. There could be system and environment specific variables involved in your situation that may be causing problems – it’s very difficult to say without more details. If you want you can post a short snippet of the code that’s causing problems, and I’ll offer what help I can, but outside of that, if none of the suggestions in my post solved the problem, then I would start looking on Stack Overflow for solutions more specific to your situation and setup. Thanks for visiting the site and good luck with getting things up and running.
      -Brent

    1. Hi Ben, it depends on your set up and machine. I use Expo and just test things on my physical device, but I’m sure you can get it up and running on your emulator as well, it just may take some patience and stack overflowing. To test things out, I load it on my device (or let’s say an emulator) and then start another instance of the app on Expo using their online emulator to send messages back and forth. If you don’t use Expo, then you will need to start another instance of the app on another emulator to test socket io events. Thanks for visiting the site. -Brent

  6. I really don’t know what to do here “Note: initialize socketIO in componentDidMount() in your main App.js file for your React-Native app”.

    1. Hi Digitz, I updated the blog post with an example of my Socket IO module and how I export and use it in componentDidMount() in App.js. Checkout the addition to the Note you mention in the post now. Let me know if that helps. Thanks for visiting. -Brent

  7. Hi, In local machine it was working fine,.
    If i generate apk for production, socket io not connecting to my production server. Please any one help on this.

  8. It is surprisingly hard to find a post on getting socket io and react native working. Thank you for putting in the effort to make this post! Really helped me in my project!!!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.