2

I am at a complete loss as to why this is not working, I am new to using Hooks in react however want to try.

This app basically connects sockets.io to the server using sockets-auth server emits the time every 1s <- this shows me that the connection is definitely live. It then uses sockets.emit to receive an array of data, this functions. The part that doesn't is a simple button press fails to achieve anything (see both 'Save Changes' buttons at bottom of React element). No error, no response, no acknowledgment at all. I have tried it inline, in its own function. The exact same server routes are functional simultaneously running a separate app with class components.

Help would be much appreciated. Anyway here is some code..

Client-Side (React.js)

import React, { Component,useState, useEffect } from "react";
import io from "socket.io-client";
import './Secret.css'

const Secret = () => {
  const [time, setTime] = useState('');
  const [userlist, setUserlist] = useState([]);



  const socketUrl = 'http://localhost:3001';
  let socket = io(socketUrl, {
    autoConnect: false,
  });


  useEffect(() => {
    const requestOptions = {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ title: 'React POST Request Example' })
  };

  fetch('/api/connectsocket', requestOptions)
      .then(async response => {
          const data = await response.json();

          if (!response.ok) {

              const error = (data && data.message) || response.status;
              return Promise.reject(error);
          }


          console.log(data)
          connectSocket(data)
      })
      .catch(error => {

          console.error('There was an error!', error);
      });    

  }, [socketUrl]);



  const connectSocket= (data)=>{
    let dataUser = data
    console.log(dataUser.email)
    let error = null;



  socket.on('connect', () => {
    console.log('Connected');


    socket.emit('authentication', {
      token: dataUser.email,
      i: dataUser.i
    });


  });

  socket.on('unauthorized', (reason) => {
    console.log('Unauthorized:', reason);

    error = reason.message;

    socket.disconnect();
  });

  socket.on('disconnect', (reason) => {
    console.log(`Disconnected: ${error || reason}`);


    error = null;
  });




  socket.on("admin connected", data => {
    socket.emit('admin userlist', { get:'x',for:'who' }, (error) => {
      if(error) {
        alert(error);
      }
    });
     console.log(data)
   });
   socket.on("admin user list", data => {
   setUserlist(data)
     console.log(data)
   });


  socket.on("FromAPI", data => {
   setTime(data)
    console.log(data)
  });


  socket.open();

  }

const sendMessage = (x)=>{

console.log(x)
  socket.emit('hello', 'JSON.stringify(x)');

}

const doSomething = ()=>{


  socket.emit('chatmessage', {msg:"Hello"});

  }


  return (
    <div>
    <div className="outerContainer">
      <div className="container">
         {time}
         <button onClick={sendMessage}>Save Changes</button>
         <button onClick={doSomething}>Save Changes</button>




          {userlist.map(user => (
          <tr key={user.id} value={user.id}>
            <td>{user.email}</td>
            <td>{user.email}</td>
            <td>{user.email}</td>
          </tr>
            ))}




      </div>

    </div>
    </div>
  );

}
export default Secret

Server-side (Node.js)

const http = require('http');
const cors = require('cors');
const express = require('express');

const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const io = require('socket.io')();
const socketAuth = require('socketio-auth');


//custom modules
const router = require('./modules/router');
const db = require('./modules/db.js');
const prettyDate = require('./modules/prettyDate.js');
const sortArray = require('./modules/sortArray.js');

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

io.attach(server);

app.use(cors()); ///delete for production
app.use(bodyParser.urlencoded({ extended: true }));
app.use(fileUpload({
    createParentPath: true
}));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(router);
app.use(express.static('public'))

db.i12345.sessions.persistence.setAutocompactionInterval(400)

 ////Sessions Store; not important if you want to run the code without
function setUser(id,user,i){
console.log('setuser')
let institution = i
  db[institution].sessions.find({ user:user }, function (err, docs) {
 if(docs.length){
  db[institution].sessions.update({user:user  }, { $set: { id: id } }, { multi: true }, function (err, numReplaced) {

  });


 } else {
  var d = new Date();
  var n = d.getTime();
  var doc = { user: user
               , id: id
               , t:n

               };

    db[institution].sessions.insert(doc, function (err, newDoc) {  

      });
 }



});
}




///user verification; could easily mock; if wanting to actually run code
async function verifyUser (token,i) {
    var institution =i
  return new Promise((resolve, reject) => {
    // setTimeout to mock a cache or database call
    setTimeout(() => {

      var user = new Promise((resolve,reject) =>{
        db[institution].users.find({email:token}, function (err, docs) {
            if(docs.length){

                resolve(docs);
             } else {
             reject(false)
             }

              });
    });


      if (!user) {
        return reject('USER_NOT_FOUND');
      }

      return resolve(user);
    }, 200);
  });
}



//// Sockets auth implementation
socketAuth(io, {

  authenticate: async (socket, data, callback) => {
    const { token, i } = data;
    console.log(data)

    try {
      const user = await verifyUser(token, i);




      socket.user = user;
      socket.i = i
      console.log(i)

      return callback(null, true);
    } catch (e) {
      console.log(`Socket ${socket.id} unauthorized.`);
      return callback({ message: 'UNAUTHORIZED' });
    }
  },
  postAuthenticate: async (socket) => {
    console.log(`Socket ${socket.id} authenticated.`);
    console.log(socket.user)
    setUser(socket.id,socket.user, socket.i)

    socket.emit('empty list', {queryList:true});

    io.emit('admin connected', {admin:true});

    socket.conn.on('packet', async (packet) => {
      if (socket.auth && packet.type === 'ping') {
      }
    });
    socket.on('chatmessage', (msg) => {
      io.emit('chatmessage', msg);
      console.log(msg);
    });
    socket.on('hello', (msg) => {
        io.emit('chatmessage', msg);
        console.log(msg);
      });

    socket.on('get tasks', (get) => {
     let i = socket.i
     let user = socket.user
     getTasksChunk(get,i,user)

      });

      socket.on('admin userlist', (get) => {
        let i = socket.i
        let user = socket.user

        adminGetUserList(get,i,user)


         });

         socket.on('admin roles', (data) => {
            let i = socket.i
            let user = socket.user
                console.log(data)
                console.log('reaced')



             });




    interval = setInterval(() => getApiAndEmit(socket), 1000);

  },



  disconnect: async (socket) => {
    console.log(`Socket ${socket.id} disconnected.`);

    if (socket.user) {

    }
  },
})

function getTasksChunk(get,i, user){
    console.log(get,i,user);
    let institution = i

        db[institution].tasks24.find({}, async function (err, docs) {
            if(docs.length){
                for(i=0;i<docs.length;i++){
                    docs[i].location = `Ward: ${docs[i].location.Ward} Bed: ${docs[i].location.Bed}`
                    docs[i].patient = docs[i].patient.join(' | ')
                    docs[i].timestamp = prettyDate(new Date(+docs[i].timestamp))
                  } 
                  console.log(docs)
                let sorted = await sortArray(docs,'timestamp')
                let chunk = sorted.slice(0,10)

               io.emit('tasks in', chunk);
             } else {

             }

              });





}

const getApiAndEmit = socket => {
    const response = new Date();
    // Emitting a new message. Will be consumed by the client
    socket.emit("FromAPI", response);
  };


  ///////ADMIN????????

 function adminGetUserList(get,i,user){
     var institution = i
     console.log('hello')
    db[institution].users.find({}, async function (err, docs) {
        if(docs.length){

              console.log(docs)
            let sorted = await sortArray(docs,'timestamp')


           io.emit('admin user list', sorted);
         } else {

         }

          });
  }
server.listen(process.env.PORT || 3001, () => console.log(`Server has started.`));

1 Answer 1

10

You must store your socket instance in a ref otherwise you would loose the connected socket instance when your component re-renders.

In short you need the socket reference to be the same across renders

  const socketUrl = 'http://localhost:3001';
  let socket = useRef(null);

  useEffect(() => {
      socket.current = io(socketUrl, {
           autoConnect: false,
      });
      ...
  }, [socketUrl]);

Now note that whereever you are using socket you would use socket.current.

Ex:

 socket,.current.on('hello', (msg) => {
    io.emit('chatmessage', msg);
    console.log(msg);
  });
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.