socket.io로 채팅을 만들면서 state가 초기화 되는 현상을 만났다.
const [chat, setChat] = useState([{ message: 'Hello!' }]);
socket.on("message", (message) => {
setChat([...chat, { message: message }]);
});
위 코드처럼 작성했을 경우, 초기의 chat값만 남아있고, 다른 값들은 추가되지 않았다.
변경된 값들도 초기화 되어버렸다.
const [chat, setChat] = useState([{ message: 'Hello!' }]);
socket.on("message", (message) => {
setChat((prevChat) => [...prevChat, { message: message }]);
});
위 코드처럼 작성하니 기존의 값들도 유지되고, 초기화 되지도 않았다. 물론 추가되는 값들도 정상적으로 추가되었다.
되지 않았던 이유는, useState는 비동기처리를 하기 때문에 상태를 즉시 업데이트하지 않고,
이전 상태에서 새로운 값을 추가해야했기 때문에 콜백함수를 넣어줘야했다.
https://stackoverflow.com/questions/63094510/why-is-my-state-array-resetting-to-empty
const [number, setNumber] = useState(0);
const numberCount = () => {
setNumber(number + 1);
setNumber(number + 1);
setNumber(number + 1);
}
위 코드를 보면 +3을 해줄 것 같지만, +1만 해준다.
리액트에서 더 나은 성능을 위해 여러개의 state 변경을 하나로 묶는다.
16ms 동안 변경되는 값들을 하나로 묶는다. (배치라고 부른다)
useState 속을 들여다보면,
useState는 ReactCurrentDispatcher의 useState 매서드를 실행시키는 것이며,
ReactCurrentDispatcher가 객체이기 때문에 같은 key값은 덮어쓰므로 마지막 setState만 실행된다.
const [number, setNumber] = useState(0);
const numberCount = () => {
setNumber((num) => num + 1);
setNumber((num) => num + 1);
setNumber((num) => num + 1);
}
위 코드처럼 setNumber안에 함수를 넣어서 state의 값을 변경하면 +3이 되는 걸 볼 수 있다.
https://velog.io/@alstnsrl98/useState%EB%8A%94-%EB%8F%99%EA%B8%B0-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%8F%99%EA%B8%B0%EC%A0%81-%EC%B2%98%EB%A6%AC
결국, 위 링크에 담긴 내용처럼, 콜백함수로 동기적 처리를 할 수 있다.