이전 글에서 함수가 끝날 때까지 state의 값은 변하지 않는다는 것을 배웠다. 그렇다면 한 함수 안에서 state를 변경하고, 그 값을 바로 사용해야 한다면 어떻게 해야 할까?
내가 고민한 코드는 아래 코드였다.
const handleBlur = useCallback(
(e, i) => {
let updated = [...edited];
if (e.target.innerText === text[i]) {
updated[i] = null;
} else if (e.target.innerText.trim() === "") {
updated[i] = "-";
} else {
updated[i] = e.target.innerText;
}
setEdited(updated);
// patchUserSymbol();
},
[edited, text]
);
중요한 건 저 주석처리 된 patchUserSymbol()이다. handleBlur()에서 edited라는 상태를 변경한 후 바로 그 값을 서버에 전달해야 했는데 patchUserSymbol()을 호출한 시점에서 edited는 그대로이기 때문에 한 박자 늦게(즉, 마지막에 변경한 상태를 제외하고) 전달된 것이다.
이 문제를 해결하기 위해 patchUserSymbol()을 useEffect에서 호출하고 의존성 배열에 patchUserSymbol을 넣어줬다.
useEffect(() => {
patchUserSymbol();
}, [patchUserSymbol]);
그리고 patchUserSymbol()은 useCallback으로 선언해 변경을 감지하고 싶은 상태들을 의존성 배열에 넣어줬다.
const patchUserSymbol = useCallback(async () => {
try {
const symbolObj = {
enter: enterSymbol,
pause: pauseSymbol,
mouse: mouseSymbol,
slash: slashSymbol,
highlight: highlighted,
edit: edited,
};
const res = await api.patch(
`/presentations/${presentation_id}/speeches/${speech_id}`,
{
params: {
"presentation-id": presentation_id,
"speech-id": speech_id,
},
userSymbol: JSON.stringify(symbolObj),
}
);
} catch (err) {
console.log("patch user symbol error:", err);
}
}, [
enterSymbol,
pauseSymbol,
mouseSymbol,
slashSymbol,
highlighted,
edited,
presentation_id,
speech_id,
]);
이렇게 하면 의존성이 변경되지 않는 한 함수가 다시 렌더링되지 않기 때문에 불필요한 렌더링을 방지할 수 있다.
앞서 useEffect에 patchUserSymbol을 의존성에 넣어줬기 때문에, patchUserSymbol()은 처음 렌더링 때와 patchUserSymbol()의 의존성이 변경될 때마다 호출된다.
728x90
'React' 카테고리의 다른 글
useReducer로 useState 리팩터링 하기 (1) (0) | 2023.09.15 |
---|---|
useReducer (0) | 2023.09.12 |
State 작동 방식 (0) | 2023.08.08 |
styled component에 css animation 적용 (재생되는 텍스트 만들기) (0) | 2023.07.18 |
Error Boundary (0) | 2023.07.15 |