Reputation: 357
Basically I think my question is why is it that why can't i access allUserMessages from my state within useEffect with nothing in its dependency array? More details below. Thank you.
I am trying to push to an array in my state with useeffect like componentDidMount for incoming websockets data. But when messages come in it seems to push the most recent message but doesnt keep the rest of the array because in my chat log im only getting the most recent message sent instead of a log of all the messages. When I take out the empty dependencies array in my useeffect function, it can push to the array and has the full chat log, but it seems to receive the message recursively with each message in my array so by the 5th or 6th message the app becomes very slow It console logs the same message a bunch of times and increases with each message. Please have a look at my code if you wouldn't mind and let me know if you have any ideas. I really aprpreciate it.
const socket = io.connect()
const Community = () => {
const [userMessage, setUserMessage] = useState("");
const [allUserMessages, setUserMessages] = useState([])
const [showMentions, setShowMentions] = useState(false)
const [activeUsersForMentions, setActiveUsersForMentions] = useState([])
const [mentionIDs, setMentionIDs] = useState([])
const [userID, setUserID] = useState()
useEffect(()=>{
socket.on("incomingMessage", (data) => {
console.log(data);
socket.emit("joinRoom", {roomid: 'lounge'})
console.log('joining room');
//get the current list of all messages on the channel
//push the new message with the info from data
let isUserMentioned = false;
if(typeof data.mentions.find(x=>x === userID) != 'undefined'){
isUserMentioned = true;
}
console.log(allUserMessages);
//set state again with modified array to include the new message
setUserMessages([...allUserMessages, {first_name: data.first_name,
last_name: data.last_name,
avatar: data.avatar,
message: data.message,
account_type:data.account_type,
isMentioned: isUserMentioned}])
})
},[])
Upvotes: 4
Views: 1098
Reputation: 1074198
Because the dependencies array is empty, within your callback, you're guaranteed that allUserMessages
will be []
(its initial state), because your callback closes over that initial state and is only called once, after the component is initially created. But you get messages from the socket repeatedly, even after updating your state.
To fix it, use the callback version of setUserMessages
:¹
setUserMessages(allUserMessages => [...allUserMessages, {first_name: data.first_name,
// −−−−−−−−−−−−−^^^^^^^^^^^^^^^^^^
last_name: data.last_name,
avatar: data.avatar,
message: data.message,
account_type:data.account_type,
isMentioned: isUserMentioned
}]);
That way, you'll always get the up-to-date version of allUserMessages
, instead of only the version that was current as of when your component was first created.
In general, in React, if you're updating a state item based on an existing state item, 99% of the time you want to use the callback version of the state setter so that you always have the most up-to-date state.
¹ It really should be called setAllUserMessages
(or the state item should be userMessages
rather than allUserMessages
) because the state item is allUserMessages
. That's just convention, but it's the overwhelmingly common convention.
Upvotes: 7
Reputation: 141
Right now, because you have an empty dependencies array, your useEffect hook is only running once when you load the component. If you remove the dependecies array altogether, your useEffect will keep running indefinitely. You need to set a proper dependency in the array that will make your useEffect hook run everytime that value changes.
Upvotes: 0