Reputation: 175
I have a stuck with avoiding component re-render when I use a Websocket for receiving data and update them to UI. I have a component named A and I use a Websocket into it for receiving a real-time message and then show it to UI. I use "useEffect" hook like that:
function User() {
let ws = new Websocket(host);
let [users, setUser] = useState([]);
useEffect(() => {
let message = [];
ws.onmessage = evt => {
message = JSON.parse(evt.data);
setUser(message);
}}, [users]);
return (
<div className="user-table">
<Table users={users} />
</div>
)
}
Because the Websocket frequently has the new data (1 second), it causes the component always update. So, is there any way for avoiding this problem? (caching or something like that)
Upvotes: 1
Views: 4930
Reputation: 370789
The problem here is not the socket in itself, but the fact that your useEffect
dependency array contains a state, and that the useEffect
callback adds a listener, and that the callback changes the state. Every time setUser
is called, users
changes - and when users
changes, the useEffect
runs again, because one of its dependencies changed.
Remove users
from the dependency array, and only declare the socket once, in the useEffect
so that you only have one socket (per User
, at least...) active at a time.
function User() {
const [users, setUsers] = useState([]);
useEffect(() => {
const ws = new Websocket(host);
ws.onmessage = evt => {
setUsers(JSON.parse(evt.data));
};
// Close socket on unmount:
return () => ws.close();
}, []); // <-- empty dependency array; only run callback once, on mount
return (
<div className="user-table">
<Table users={users} />
</div>
);
}
Also note:
const
over let
in ES6users
and setUsers
. (If you have only a single user, use user
and setUser
)If there's any chance of there being more than one User
, it would be better to create the socket just once in the parent, then pass it down as a prop; that way, you won't be creating multiple sockets which all do the same thing.
Upvotes: 2