채팅을 보낼 때 채팅 데이터를 state에 저장하고, 보낸 거에 대한 서버 응답 data도 같이 log에 저장해야 했었음.
근데 setState가 비동기적으로 동작해서 잘 저장되지 않는 이슈 발생
const [msg, setMsg] = useState({}); // 채팅 메세지 정보들 담을 state
const [log, setLog] = useState([]); // 채팅 로그
ws.onmessage = () => {
const receivedMessage = JSON.parse(event.data);
if (receivedMessage.method === 'SENT') {
setMessage((prev) => {
return {
...prev,
chatId: receivedMessage.chatId,
read: receivedMessage.read
};
});
setLog((prev) => [message, ...prev]); // 빈 객체가 들어감
};
};
const send = () => {
...
const messageObj = {
content: inputRef.current.value,
type: 'TEXT',
roomId: otherUser.room_id,
method: 'SEND',
date: timestamp.toISOString().split('T')[0], // 현재 날짜의 YYYY-MM-DD 형식
time: timestamp.toTimeString().split(' ')[0], // 현재 시간의 HH:MM:SS 형식
chatId: 0, // 임시
read: false, //임시
};
setMessage(messageObj);
};
해결하려면 useState()의 동작을 좀 이해할 필요가 있었다.
상태를 변경하기 위해 setState를 호출해도 즉시 변경되지 않는다.
→ 비동기적으로 작동함
페이지를 구성하는 수많은 state들이 변경될 때마다 리렌더링된다면 성능이 저하되기 때문임
그래서 react는 batch를 통해 setState를 한 번에 처리하고 리렌더링함
batch: 16ms 동안 변경된 상태 값들을 하나로 묶어 처리
동기적으로 처리하는 방법
1. useEffect()
useEffect(()=>{
//code
},[dependency])
dependency가 변경될 때마다 useEffect 내부의 함수가 실행됨
setState((prev)=>prev+1);
함수를 인자로 받으면 prev가 가장 최신인 상태로 업데이트된 값을 받을 수 있음
고친 코드
if (receivedMessage.method === 'SENT') {
setMessage((prev) => {
return {
...prev,
chatId: receivedMessage.chatId,
read: receivedMessage.read
};
});
}
...
useEffect(() => {
// 최종 message만 log에 담기 위한 조건
if (message.chatId !== 0 && message.read !== undefined) {
setLog((prev) => [message, ...prev]);
}
}, [message]);
이거 보고 해결
https://velog.io/@rkio/React-useState는-비동기이다.-동기-처리하려면
https://ssabi.tistory.com/69