setState함수는 단순히
상태를 바꾸는 함수가 아니라, 바꿔달라고 요청해주는 함수
입니다.
그러므로 하나의 이벤트 핸들러 내에서 setState가 여러 번 호출된다면, 이벤트 핸들러 함수가 끝난 시점에 state를 일괄적으로 업데이트하고 리렌더링합니다
“setStae가 여러개 있으면 마지막에 다 끝나고 일괄처리”
이렇게 이해하지 말고, “비동기로 처리”가 된다고 이해해야 하는 것이 더 정확합니다
여러개의 setState함수가 있을 때
리액트가 setState를 동기로 처리하면
하나의 상태값 변경 함수가 호출될 때마다 화면을 다시 그리기 때문에 성능 이슈가 생길 수 있으며,
만약 동기로 처리하지만 매번 화면을 다시 그리지 않는다면 UI 데이터와 화면 간의 불일치가 발생해서 혼란스러울 수 있습니다
import React, { useState} from 'react'
const App = () => {
const [list, setList] = useState([])
const [number, setNumber] = useState('')
...
const onInsert=e=>{
const nextList=list.concat(parseInt(number))
setList(nextList)
console.log('리스트 업데이트')
setNumber('')*
}
return (
<div>
...
</div>
)
}
export default App
위의 코드를 실제로 실행시켜 보면
총 2번의 리렌더링이 발생할 것 같지만,
한번에 리렌더링
이 진행이 됩니다
또한 이벤트 핸들러 함수 안에서 또다른 이벤트 핸들러가 존재한다면
최종적으로 한 싸이클에서 호출된 모든 이벤트 핸들러가 종료되고 나서 배치로 처리가 됩니다
import React, { useState } from 'react'
const App = () => {
const [input, setInput] = useState('')
const [flag, setFlag] = useState(false)
const onChange = (e) => {
setInput(e.target.value)
check()
}
const check = () => {
setFlag((prev) => !prev)
console.log(flag)
}
console.log('render')
return (
<div>
<input value={input} onChange={onChange}></input>
</div>
)
}
export default App
위의 코드는
여기서 onChange() 와 check()까지 전부 진행하고 난 다음에 상태 업데이트가 배치로 처리되는 것입니다
이처럼 리액트의 state를 업데이트하는 데있어서, 비동기적으로 작동하는 속성은 여러개의 state를 다룰 때 퍼포먼스측면에서 유리합니다
반대로 만약 동기적으로 작동했다면 리렌더링 과정이 지나치게 많아집니다
state1 업데이트,리렌더링 - state2 업데이트,리렌더링 - state3 업데이트,리렌더링
그래서 비동기 방식을 이용해서 여러 state를 동시에 업데이트하는 경우,
리액트는 state를 batching
하여 업데이트를 진행합니다
쉽게 말하지면, 데이터를 실시간으로 처리하는게 아니라, 일괄적으로 모아서 처리하는 작업
을 의미합니다
가령, 하루동안 쌓인 데이터를 배치작업을 통해 특정 시간에 한꺼번에 처리하는 경우가 이에 해당합니다
은행의 정산작업과 같은 업무에서 이런 일괄처리를 수행하게 되며 사용자에게 빠른 응답이 필요하지 않은 서비스에 적용할 수 있으며, 특정 시간이후에는 자원을 거의 소비하지 않는 것이 특징입니다
즉, 여러 상태들을 한번에 합친 다음에 리렌더링-업데이트를 한다는 것입니다
이러한 특성 때문에 만약
같은 state를 여러번 업데이트
하게 되면 우리가 예상하는 것과 다른 결과를 내놓게 되는 치명적인 경우가 있습니다
연속해서 동일한 state에 대한 setState 함수를 실행시킬 경우 Batching으로 인해 가장 마지막에 호출된 setState함수만 overwrite되어 호출 되는 것입니다
위의 setList , setNumber의 비동기 처리 예시는 , 같은 상태가 아니라 서로 다른 상태를 업데이트 하는 것
이었지만 , 아래의 예시 같은 경우는 value라는 하나의 상태를 여러번 업데이트
하고 있습니다
function App() {
const [value, setValue] = useState(0)
const onClick = () => {
setValue(value+1)
setValue(value+1)
setValue(value+1)
}
return (
<>
<button onClick={onClick}>+</button>
{value}
</>
)
}
export default App
여기서 한번의 클릭으로 value의 값이 3씩 늘어날 것을 예상했지만
실제로는 1씩 늘어나게 됩니다.