Home > OS >  socket.io broadcasting not working with React
socket.io broadcasting not working with React

Time:10-21

I am currently trying to build a connection between a Node.js application in the backend and a React application in the frontend. The connection from the frontend to the backend seems to work without any problems. Unfortunately, the React application, on the other side, cannot accept any data.

The socket.on(...) function throws an error:

dashboard.js:20 Uncaught TypeError: Cannot read properties of null (reading 'on')

I can not explain where the error lies.

app.js (mounting point of the React app):

import React, { useEffect, useState } from 'react'; 
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import io from 'socket.io-client';
import Dashboard from "./compontents/views/dashboard/dashboard";

function App() {
    const [socket, setSocket] = useState(null);

    useEffect(() => {
        const newSocket = io(`http://${window.location.hostname}:8040`);
        setSocket(newSocket);

        return () => newSocket.close();
    }, [setSocket]);

    return (
        <Router>
            <div className="app">
                <div className="app__view">
                    <Switch>
                        <Route exact path="/">
                            <Dashboard socket={socket} />
                        </Route>
                    </Switch>
                </div>
            </div>
        </Router>
    );
}

export default App;

dashboard.js (child component):

import React, { useEffect, useState } from 'react';

import { Link } from "react-router-dom";
import FeatherIcon from 'feather-icons-react';
import LargeButton from "../../buttons/largeButton/largeButton";

function Dashboard({ socket }) {
    function toggleLight(type) {
        if(type) {
           // this function works fine
            socket.emit("toggle light", type);
            console.log(type);
        }
    }

    useEffect(() => {
        // this line is causing the error
        socket.on('toggle button', (type) => {
            console.log(type);
        });
    }, [socket]);

    return(
        <div className="view">
            <div className="all">
                <LargeButton icon="sun" text="Alles einschalten" event={toggleLight} />
                <LargeButton icon="moon" text="Alles ausschalten" event={toggleLight} />
            </div>
        </div>
    )
}

export default Dashboard;

CodePudding user response:

It seems like your <Dashboard/> component are mounting before the socket instance are ready to go. Socket connection is an a async procedure so you must take this on mind when you use it.

Try change your app.js to this:

import React, { useEffect, useState } from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import io from 'socket.io-client';
import Dashboard from './compontents/views/dashboard/dashboard';

function App() {
  const [socket, setSocket] = useState(null);

  useEffect(() => {
    const newSocket = io(`http://${window.location.hostname}:8040`);
    setSocket(newSocket);

    return () => newSocket.close();
  }, [setSocket]);

  if (!socket) { 
      // catch and show some loading screen
      // while the socket connection gets ready
    return <div>Loading...</div>;
  }

  return (
    <Router>
      <div className="app">
        <div className="app__view">
          <Switch>
            <Route exact path="/">
              <Dashboard socket={socket} />
            </Route>
          </Switch>
        </div>
      </div>
    </Router>
  );
}
  • Related