리액트에서 데이터를 UI에 반영하기 위해서는 데이터를 상태값으로 저장하고 유지해야 한다.
이 후 상태값이 변화하면 리액트는 이를 인식하고 UI를 그에 맞게 리렌더링한다.
그럼 함수형 프로그래밍/훅을 이용해서 어떻게 상태를 건드릴 수 있을까?
리액트에선 useState라는 내장 훅을 지원하며 이를 이용해 컴포넌트에 상태값을 추가할 수 있다.
아래 코드를 보자.
const func1 = () => {
const [count, setCount] = useState(0);
// 버튼을 누르면 카운트가 올라가는 예제
const onClick = () => {
setCount(count + 1);
}
return (
<div>
<p>count</p>
<button onClick={onClick}></button>
</div>
)
}
useState훅은 상태와 상태 변경함수를 반환한다.
count는 상태이며 setCount는 상태값 변경함수로 count(상태)에 직접접근하여 값을 변경할 수 없다.
리액트는 상태값 변경함수가 호출되면 해당 컴포넌트를 다시 그린다.
다만 많은 상태값이 한번에 호출을 하려고 하면 성능 저하(너무 많은 렌더링의 발생)가 일어날 수 있으므로 batch(일괄적으로)
처리한다.
const func1 = () => {
const [count, setCount] = useState(0);
// 버튼을 누르면 카운트가 올라가는 예제
const onClick1 = () => { // 1 올라감
setCount(count + 1);
setCount(count + 1);
}
const onClick2 = () => { // 2 올라감
setCount(prev => prev+1);
setCount(prev => prev+1);
}
return (
<div>
<p>count</p>
<button onClick={onClick1}></button>
<button onClick={onClick2}></button>
</div>
)
}
따라서 useState는 비동기로 처리되는데, 위 예제의 onClick1
처럼 단순히 두번의 상태값 변경 함수 호출로 2를 더할 수 없다.
그러므로 위와 같은 상황에선 onClick2
처럼 함수를 인수로 넣어 처리를 하면 인수로 넣어진 함수는 호출되기 직전의 상태값을 받기 때문에 정상적으로 2가 더해질 수 있게된다.
const func1 = () => {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
// 버튼을 누르면 카운트가 올라가는 예제
const onClick = () => { // count1, count2 1씩 올라감
setCount1(count1 + 1);
setCount2(count2 + 1);
}
return (
<div>
<p>count</p>
<button onClick={onClick}></button>
</div>
)
}
useState는 비동기로 처리되지만 순서는 보장한다.
위 예제와 같이 서로 다른 상태값 변경함수가 연달아 있을 때, 상태값 변경함수들은 호출이 되는 순서대로 상태값이 변경이 된다.