0

Server:

io.on('connection', (socket) => {
  const username = socket.id;

  socket.emit('connection', username);
  socket.emit(
    'products',
    JSON.parse(fs.readFileSync(`${path.join(__dirname)}/db.json`, 'utf-8'))
  );

  socket.on('update', (data) => {
    console.log(data);
    const { id, value, replace } = data;
    const products = JSON.parse(
      fs.readFileSync(`${path.join(__dirname)}/db.json`, 'utf-8')
    );

    products.map((item) => {
      if (item.id === id) {
        item[replace] = value;
      }

      return item;
    });

    fs.writeFileSync(
      `${path.join(__dirname)}/db.json`,
      JSON.stringify(products)
    );

    socket.emit('products', products);
  });
});

MyComponent:

import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import socketClient from 'socket.io-client';
import Table from '../components/TableProducts';

import { updateDataTable, getData } from '../redux/actions/products';
import { getProducts } from '../redux/selectors/products';

const TableContainer = () => {
  const dispatch = useDispatch();

  const products = useSelector((state) => getProducts(state.products));
  const socket = socketClient.connect('http://localhost:9000/');

  useEffect(() => {
    socket.on('products', (data) => {
      dispatch(getData(data));
    });
  }, []);

  const handleChange = (object) => {
    // const {id, name, value} = data;
    dispatch(updateProduct(object));
    socket.emit('update', object);
  }

  return (
    <Table data={products} />
  );
};

export default TableContainer;

After executing handleChange, my socket is sent to the server and everything is processed well there. The problem is that apparently my component is updated when receiving a socket from the server, thereby executing useEffect creating a new connection.
UPDATE (Add my index.js file):

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';

import 'bootstrap/dist/css/bootstrap.min.css';
import './scss/_base.scss';

import store from './redux/store';
import App from './App';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

Лукас
  • 213
  • 1
  • 4
  • 12

1 Answers1

0

The connection is triggered many times probably because the component is remounting everytime in your app and firing const socket = socketClient.connect('http://localhost:9000/');. You can use React Context, to change that behaviour and accessing the socket instance in any component in your app this way:

socket.js

import React from "react";
import io from "socket.io-client";

export const socket = io("http://localhost:9000/");

export const SocketContext = React.createContext();

index.js

import { SocketContext, socket } from "./socket";

ReactDOM.render(
  <React.StrictMode>
    <SocketContext.Provider value={socket}>
      <App />
    </SocketContext.Provider>
  </React.StrictMode>,
  document.getElementById("root")
);

component.js

import React from "react";
import { SocketContext } from "./socket";

export const TableContainer = () => {
   const socket = React.useContext(SocketContext);
   ...
}

This way, connection is triggered one time.

Cássio Lacerda
  • 1,554
  • 1
  • 12
  • 14
  • @Лукас Did you try the solution? – Cássio Lacerda May 24 '21 at 17:28
  • Your example works, but I'm using the state manager "react-redux", and I have to put your example from index.js inside . I have a new websockets connection created when a dispatch occurs to change the store. – Лукас May 28 '21 at 03:42
  • It's strange because my scenario is the same with React Redux with wrapping too. My dispatchs don't change the socket instance connection because it occurs once in `socket.js` file with `export const socket = io("http://localhost:9000/");` – Cássio Lacerda May 28 '21 at 14:15
  • 1
    Everything works, the funny problem was that after fs.writeFile nodemon restarted the server, thereby creating new connections. – Лукас Jun 10 '21 at 14:31