how to prevent nextjs component from re rendering whenever a new message is received through wsocke?
Answered
Pacific sandlance posted this in #help-forum
Pacific sandlanceOP
hey guys, I've noticed that if I connect to my websocket and receive messages, it rerenders the component and re establishes the component, I've already added code logic to not connect a second time but is there an other way to prevent the component from re-rendering?
Answered by Pacific sandlance
Ah I see what is happening, looked further into it and if I disable react strict mode everything works perfectly
24 Replies
@Pacific sandlance hey guys, I've noticed that if I connect to my websocket and receive messages, it rerenders the component and re establishes the component, I've already added code logic to not connect a second time but is there an other way to prevent the component from re-rendering?
move the websocket connection 1 level up and pass it using props to the child component so that even if it re renders nothing happens
@@ts-ignore move the websocket connection 1 level up and pass it using props to the child component so that even if it re renders nothing happens
Pacific sandlanceOP
Where can I can find more info in docs?
@Pacific sandlance Where can I can find more info in docs?
you don't need docs for it
just connect to your websocket in parent component and pass it as prop to child
Pacific sandlanceOP
oh I see
Initiate the connection in index.js for example and emit the received data to <Child props={props} /> ?
@@ts-ignore just connect to your websocket in parent component and pass it as prop to child
Pacific sandlanceOP
still connects 2 times smh
scratched the reusable hook completely, I will just use a simpler one in every class because I cba at this point fixing it
Asian black bear
How are you connecting to a we socket that causes any re-render at all?
Are you keeping something in state that belongs in a ref?
@Asian black bear Are you keeping something in state that belongs in a ref?
Pacific sandlanceOP
no
import { useEffect, useRef } from 'react';
import EventEmitter from 'events'; // You can also use Node's native events module
const useSocketListener = (socketUrl, callback) => {
const eventEmitterRef = useRef(new EventEmitter());
const cbCalledRef = useRef(false);
useEffect(() => {
const listen = () => {
let lastReceived = Date.now();
const socket = new WebSocket(socketUrl);
let resetId = setInterval(() => {
if (Date.now() > lastReceived + 10 * 1000) {
try {
socket.ping();
} catch (err) {}
}
if (Date.now() - lastReceived > 20 * 1000) {
try {
socket.terminate();
} catch (err) {
clearInterval(resetId);
listen();
}
}
}, 15000);
socket.addEventListener('open', () => {
console.log(`Connected to ${socketUrl}`);
lastReceived = Date.now();
if (!cbCalledRef.current) {
cbCalledRef.current = true;
callback(eventEmitterRef.current);
}
});
socket.addEventListener('close', () => {
clearInterval(resetId);
listen();
});
socket.addEventListener('pong', () => {
lastReceived = Date.now();
});
socket.addEventListener('ping', () => {
lastReceived = Date.now();
try {
socket.pong();
} catch (error) {
console.log(error);
}
});
socket.addEventListener('message', (event) => {
eventEmitterRef.current.emit('message', event.data);
lastReceived = Date.now();
});
};
listen();
return () => {
// Cleanup logic if needed
};
}, [socketUrl, callback]);
return eventEmitterRef.current;
};
export default useSocketListener; Asked chat gpt to convert a function I had from plain js to a hookexample usage:
import React from 'react';
const MyComponent = () => {
const handleEvent = (eventEmitter) => {
eventEmitter.on('message', (message) => {
console.log('Received message:', message);
});
};
useSocketListener('ws://your-websocket-url', handleEvent);
return (
<div>
{/* Your component logic */}
</div>
);
};Asian black bear
It strikes me that, being in useEffect, all of your setup code is guaranteed to be called twice
because that is just how useEffect works
Pacific sandlanceOP
I thought it run once 💀
Asian black bear
yeah it is really annoying
Pacific sandlanceOP
alright lemme check
Asian black bear
A common paradigm is to use a boolean ref to simply ignore the first run
Pacific sandlanceOP
Ah I see what is happening, looked further into it and if I disable react strict mode everything works perfectly
Answer
Pacific sandlanceOP
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: false, //previously true
}
module.exports = nextConfigThanks @Asian black bear @@ts-ignore
Pacific sandlanceOP
fyi code still needs to be finished but should be a good base