Reputation: 313
I got a component which should render a chat screen, with the message coming from socket.io.
The component :
export default function ChatScreen() {
const [name, setName] = useState("");
const [message, setMessage] = useState("");
let socket;
useEffect(() => {
socket = io("http://192.168.1.229:3000")
socket.on("chatMessage", messageObj => {
console.log(`The message sender is ${messageObj.name}`)
setName(messageObj.name)
setMessage(messageObj.message)
})
});
return (
<Text>
{name} : {message}
</Text>
);
}
the
console.log(`The message sender is ${messageObj.name}`)
Is working but it prints multiple times. The state update after isn't working at all. I get a message on console that says :
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s, a useEffect cleanup function, in ChatScreen (at SceneView.js:9)
Anyone gets it?
Upvotes: 0
Views: 2609
Reputation: 13660
The warning hits the nail on the head. You're opening a socket in useEffect()
, but you are not returning a cleanup function from it, or passing an array of dependencies to it. The first issue means that if the component is unmounted, the socket will never be closed. The second issue means that every time the component renders, a new socket will be opened. So every time a chatMessage
event occurs, yet another socket so now you have two sockets re-rendering the app every time chatMessage
occurs, and so on.
To solve the first issue, return a function from the useEffect
function which closes the socket. React will call this when the component unmounts or when the hook gets triggered due to changed dependencies.
To solve the second issue, pass an empty array for the dependencies, since you're not using anything passed via props in the effect hook. The empty array will prevent the effect hook from being run every time the component is re-rendered.
export default function ChatScreen() {
const [name, setName] = useState("");
const [message, setMessage] = useState("");
useEffect(() => {
const socket = io("http://192.168.1.229:3000");
socket.on("chatMessage", messageObj => {
console.log(`The message sender is ${messageObj.name}`);
setName(messageObj.name);
setMessage(messageObj.message);
});
return () => socket.close();
}, []);
return (
<Text>
{name} : {message}
</Text>
);
}
I would also recommend taking some time to read React's documentation on the useEffect hook: Using the Effect hook →.
Upvotes: 3