useState의 게으른 초기화

김동욱·2023년 1월 14일
0
post-thumbnail

이 글은 Kent C.Dodds의 useState lazy initialization and function updates의 'useState Lazy initialization'목차를 번역 및 의역한 문서입니다.

우리가 리액트로 작업을 하면, 'useState'를 아마도 사용할 것입니다. 여기 짧은 API 예시가 있습니다.

function Counter() {
  const [count, setCount] = React.useState(0)
  const increment = () => setCount(count + 1)
  return <button onClick={increment}>{count}</button>
}

'useState'를 초기값으로 호출하였고, 배열로 상태의 값과 업데이트를 위한 메커니즘을 반환합니다(이것을 *'상태변경함수'라고 부릅니다.). 상태변경함수를 호출하면 새로운 상태값과 useState를 다시 사용하여 새로운 상태값과 상태변경함수를 찾기 위한 컴포넌트 리랜더링을 위한 함수(상태변경함수)를 얻을 수 있습니다.

  • 상태 변경 함수: 원문에는 'state dispatch function'이라고 소개하고 있습니다.

이 내용은 우리가 리액트를 시작할때 상태에 대해서 처음 배우는 것일 겁니다. 하지만 'useState'에 대해서 유용하게 사용될 덜 알려진 특징이 있습니다.

function Counter() {
  const [count, setCount] = React.useState(() => 0)
  const increment = () => setCount(previousCount => previousCount + 1)
  return <button onClick={increment}>{count}</button>
}

이 예제에서 'useState'의 차이점은 초기값을 리턴하는 함수를 호출한다는 점과 이전 상태값을 가진 함수와 새로운 값을 반환하는 'setCount'가 있다는 점이다. 이 함수는 정확히 이전 예제와 같다. 하지만 여기엔 미묘하게 다른 점이 있다.

useState Lazy initialization

만약 우리가 'console.log'를 카운터 함수 안에 넣으면, 버튼을 누를때 마다 함수가 매순간 실행 된다는걸 알 수 있다. 이것은 일리가 있는게 왜냐하면 카운터 함수는 모든 렌더 단계마다 실행되며 버튼을 누르면 트리거는 상태를 업데이트하며 트리거도 재랜더링된다. 여기서 한가지 짚고 넘어 가야할건 만약 함수가 실행되면 안에있는 모든 코드 또한 실행된다는 말이다. 즉 우리가 만든 어떠한 변수와 인자도 만들어지며 모든 렌더마다 평가된단 말이다. 이것은 그리 큰 문제는 아니다. 왜냐하면 JS엔진은 매우 빠르고 최적화를 잘한다. 그리고 밑의 그래서 이런것들은 문제도 안된다.

const initialState = 0
const [count, setCount] = React.useState(initialState)

하지만, 상태에 들어갈 초기값이 매우 복잡하다면?

const initialState = veryVeryComplicateFunc(props)
const [count, setCount] = React.useState(initialState)
// or...
const initialState = Number(window.localStorage.getItem('count'))
const [count, setCount] = React.useState(initialState)

기억해야 할 것은 리액트가 초기값이 필요하다는 것은 초기화를 한단 의미이고, 즉 첫 랜더링 시에만 초기값이 필요하단 의미이다. 하지만 우리의 함수는 컴포넌트가 리랜더링 시 매 순간 동작한다. 우린 이 코드가 필요하든 안하든 동작하는 것을 끝내고 싶어 할것이다.

지금 보여주는 것이 게으른 초기화의 모든 것이다. 이것처럼만 코드를 작성하면 된다.

const getInitialState = () => Number(window.localStorage.getItem('count'))
const [count, setCount] = React.useState(getInitialState)

함수가 복잡한 동작을 수행하더라도 함수를 만드는 것은 빨라질것이다. 오직 함수를 호출할 때만 힘들 뿐이다. 만약 'useState'를 사용할때, 리액트는 초기값이 필요할 때만 함수를 호출할 것이다.(컴포넌트가 초기 랜더링이 됬더라도 말이다.)

이것을 '게으른 초기화(lazy initialization)'라고 부른다. 이것은 성능 최적화용이며 꼭 모든 곳에 사용할 필요는 없다. 하지만 어떤 상황에선 꽤 유용할 것이다. 하지만 이러한 특징이 존재한다는 것은 좋은 것이며 필요할 때 사용할 수 있다.(저자도 별로 사용 안했다고 함ㅇㅇ)

profile
안녕하세요. 부산에서 근무하고 있는 프론트엔드 개발자 김동욱입니다. 영어 공부 겸 개발 공부를 위해서 글을 작성하고있습니다.

0개의 댓글