useState 동기 처리

지원·2024년 5월 13일

!error

목록 보기
8/9

문제

채팅을 보낼 때 채팅 데이터를 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 내부의 함수가 실행됨

  1. setState 사용 시 콜백 함수를 인자로 전달
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

0개의 댓글