개발 공부/React
함수형 setState 업데이트
차정
2022. 7. 14. 19:32
setState는 비동기적으로 작동한다.
이벤트 핸들러안에서 호출된 setState는 setState가 얼마나 많이 호출되었든 상관없이
이벤트가 끝날때 딱 한번 리렌더링 된다. 이는 불필요한 렌더링을 막아 리액트의 성능을 높인다.
이것을 오브젝트 컴포지션으로 설명할 수 있다.
setState가 여러번 호출되면 인자로 전달된 각 객체를 추출하여 단일 객체로 merge하고,
이렇게 만들어진 단일 객체를 사용해서 상태를 업데이트 한다.
// state를 합치는 merging 작업
const resultObj = Object.assign({}, {a: 10}, {b: 20},{a: 30})
따라서 setState에 객체를 전달하여 이전상태에서 다음상태로 update하려고 하는것은 안전하지 않다.
setState는 객체뿐 아니라 함수도 인자로 받을 수 있다.
setState에 인자로 객체가 아닌 함수가 들어가면 setState는 호출된 순서대로 함수를 큐에 넣는다.
그 후에 큐의 각 함수를 호출하여 함수형 setState의 이전 상태를 전달하여 상태를 업데이트 하는 것이다.
리액트 내부동작을 흉내낸 코드로 이해해보자.
class User {
state = { score: 0 };
//let's fake setState
setState(state, callback) {
this.state = Object.assign({}, this.state, state);
if (callback) callback();
}
// multiple functional setState call
increaseScoreBy3() {
this.setState((state) => ({ score: state.score + 1 })),
this.setState((state) => ({ score: state.score + 1 })),
this.setState((state) => ({ score: state.score + 1 }));
}
}
const Justice = new User();
사용자가 increaseScoreBy3()하면 React는 여러 기능을 가진 setState를 큐에 넣는다.
//queue에 넣는 것을 흉내낸 updateQueue 배열
const updateQueue = [
(state) => ({ score: state.score + 1 }),
(state) => ({ score: state.score + 1 }),
(state) => ({ score: state.score + 1 }),
];
// 재귀적으로 배열에 있는 함수를 실행하여 updateQueue의 함수를 순차적으로 실행한다.
function updateState(component, updateQueue) {
if (updateQueue.length === 1) {
return component.setState(updateQueue[0](component.state));
}
return component.setState(updateQueue[0](component.state), () =>
updateState(component, updateQueue.slice(1))
);
}
updateState(Justice, updateQueue);
즉, 안정적으로 이전상태에 기반한 상태 업데이트를 하고싶다면, 함수형 setState를 써야한다는 것이다.
//1. setState에 객체를 넘기는 방식
setUserInput({
...userInput,
enteredTitle: event.target.value,
});
//2. setState에 함수를 넘기는 방식
setUserInput((prevState) => {
return { ...prevState, enteredTitle: event.target.value };
});
1번 방법보다 2번 방법을 써야한다.
[출처]
https://www.freecodecamp.org/news/functional-setstate-is-the-future-of-react-374f30401b6b