그동안 state의 작동 방식에 대해 제대로 이해를 못한 채로 코드를 짜서 기능이 내 의도와 다르게 돌아간 적이 많았다. setState를 사용하면 state 값이 바로 바뀌고 해당 state를 그려주는 부분이 다시 그려진다고만 알고 있었는데, 자세히 들여다보니 그게 아니었다.
const [ count, setCount ] = useState(0)
function onClickCountUp() {
setCount(5)
}
return (
<div>
<div>{count}</div>
<button onClick={onClickCountUp}>카운트</button>
</div>
)
위 코드의 동작 방식은 다음과 같다.
- 버튼을 클릭하면 setCount() 함수가 실행됨 → setCount: count 값 비교 (같으면 무시)
- 다르면
- count 값을 5로 바꾸기
- 화면 다시 그리기(리렌더링) → 위에서부터 하나씩 다시 실행
- 변수도 function도 새롭게 만들어짐
- return 안에 있는 부분도 다시 그림 → 이번에는 count가 5니까 5가 출력됨
- 실제로는 전체 화면이 다시 그려지고 있는 것
만약
const [ count, setCount ] = useState(0)
function onClickCountUp() {
setCount(7)
setCount(2)
setCount(5)
setCount(9)
setCount(1)
}
return (
<div>
<div>{count}</div>
<button onClick={onClickCountUp}>카운트</button>
</div>
)
위와 같은 코드를 실행하면 count가 7→2→5→9→1로 바뀌면서 화면이 다섯 번 그려질까? 결국엔 1 하나만 보이는데 비효율적이다.
따라서 무의미한 리렌더링을 방지하기 위해, 내부적으로 setCount(7)을 만났을 때 임시 저장 공간에 7을 넣어 놓고 바로 state를 바꾸지는 않는다. 임시 공간에 (count: 7) → (count: 2) → (count: 5) → (count: 9) → (count: 1) 을 넣어 놓고, 함수가 끝났을 때 count를 1로 바꾸고 화면을 다시 그리게 된다.
즉 화면은 한 번만 다시 그린다!
따라서
const [ isActive, setIsActive ] = useState(false)
const [ writer, setWriter ] = useState()
const [ title, setTitle ] = useState()
const [ contents, setContents ] = useState()
const onChangeWriter = (event) => {
setWriter(event.target.value)
if(writer && title && contents) {
setIsActive(true)
}
}
const onChangeTitle = (event) => {
setTitle(event.target.value)
if(writer && title && contents) {
setIsActive(true)
}
}
const onChangeContents = (event) => {
setContents(event.target.value)
if(writer && title && contents) {
setIsActive(true)
}
}
이렇게 writer, title, contents 모두 내용이 작성되었을 때 isActive로 버튼을 활성화 하려는 코드를 작성했을 때의 문제점은 내용을 한 글자씩만 입력하면 버튼이 활성화되지 않는다는 것이다. 함수 안의 if문에서는 아직 state가 변경되지 않은 상태이기 때문! 함수가 한 번 끝나고 나면 업데이트 되기 때문에 두 글자 부터는 잘 동작한다.
이 코드에서의 해결법은 event.target.value를 바로 if문에서 비교하도록 하는 것이다(state는 한 박자씩 느리기 때문에).
'React' 카테고리의 다른 글
useReducer (0) | 2023.09.12 |
---|---|
useEffect로 state 변경 바로 감지하기 (4) | 2023.08.08 |
styled component에 css animation 적용 (재생되는 텍스트 만들기) (0) | 2023.07.18 |
Error Boundary (0) | 2023.07.15 |
Styled component로 React Component 디자인 (0) | 2023.07.13 |