이번 편에서는 useState 함수와 useEffect 함수를 조금 더 유연하게 사용하는 방법을 알아보겠습니다.
import React, { useState } from 'react'
const ExpensiveComponent = () => {
const [someValue, setSomeValue] = useState(() => {
let value = 0
for (let index = 0; index < 100_0000; index += 1) {
value += 1
}
return value
})
return <div>{someValue}</div>
}
useState는 초기화 할 때에만 함수를 1번 실행하는 방식을 지원합니다.
처음 1번만 함수를 실행을 하며, 그 함수의 return 값을 State로 사용합니다.
import React, { useEffect, useState } from 'react'
const Counter = () => {
const [nickname, setNickname] = useState('Danuel')
const [count, setCount] = useState(0)
useEffect(() => {
document.title = nickname
})
const toggleNickname = () => {
if (nickname === 'Danuel') {
setNickname('Other')
} else {
setNickname('Danuel')
}
}
const decreaseCount = () => setCount(count - 1)
const increaseCount = () => setCount(count + 1)
return (
<div>
<h1>{nickname}</h1>
<button onClick={toggleNickname}>toggleNickname</button>
<h3>{count}</h3>
<button onClick={decreaseCount}>- 1</button>
<button onClick={increaseCount}>+ 1</button>
</div>
)
}
이번에는 카운트 기능과 타이틀을 바꾸는 기능을 가진 컴포넌트입니다.
이 컴포넌트는 원하는대로 작동은 잘 하지만, 찬찬히 살펴보면 카운트를 변경할 때에도 title을 변경하는 비효율적인 부분이 있습니다.
잠시 생각해보면 이전의 State와 현재의 State가 다를 때에만 useEffect 함수가 발동하는 것이 가장 효율적입니다.
...
useEffect(() => {
document.title = nickname
}, [nickname])
...
nickname을 배열에 담아 2번째 파라미터에 추가하면 이전의 State와 현재의 State가 다를 때에만 발동합니다.
...
useEffect(() => {
document.title = nickname
}, [])
...
빈 배열을 2번째 파라미터에 추가하면 처음 딱 1번만 발동합니다.
import React, { useState } from 'react'
const SECOND = 1000
const AsynchronousCounter = () => {
const [nickname, setNickname] = useState('Danuel')
const [count, setCount] = useState(0)
const decreaseCount = () => {
window.setTimeout(() => setCount(count - 1), 3 * SECOND)
}
const increaseCount = () => {
window.setTimeout(() => setCount(count + 1), 3 * SECOND)
}
return (
<div>
<p>{nickname}</p>
<p>{count}</p>
<button onClick={decreaseCount}>- 1</button>
<button onClick={increaseCount}>+ 1</button>
</div>
)
}
이번에는 비동기적으로 State를 변경해보겠습니다.
- 1
버튼 혹은 + 1
버튼을 클릭하면 3초 후에 State를 바꾸는 컴포넌트입니다.
연속적으로 클릭한 후에 값을 살펴보면 예상과는 다른 작동을 합니다. 이것은 비동기와
관련이 있습니다.
버튼을 클릭하면 3초 후에 State를 변경하는 함수를 실행하는데, 이 순간에 들어가는 값은 버튼을 클릭한 시점의 State로 이미 결정해놓았기 때문입니다.
import React, { useState } from 'react'
const SECOND = 1000
const AsynchronousCounter = () => {
// ...
const decreaseCount = () => {
window.setTimeout(() => setCount(previousCount => previousCount - 1), 3 * SECOND)
}
const increaseCount = () => {
window.setTimeout(() => setCount(previousCount => previousCount + 1), 3 * SECOND)
}
// ...
}
이런 이슈를 해결하기 위해서 React에서는 State를 변경하는 함수의 파라미터에 함수를 넘기는 방법도 지원합니다. 언뜻 보면 조금 복잡하게 보이지만, 바뀐 코드만 보면 setCount 함수에 함수를 넘겨준 것 뿐입니다.
코드에서 보듯이, 함수로 넘겨줄 때에는 '직전'의 State를 입력으로 받고 다음 State를 return 하는 형태입니다.
간단한 변경이지만 이렇게 잘 작동합니다.
좋아요와 댓글 감사합니다.
오탈자, 질문 등은 언제든지 댓글로 달아주세요!