본문 바로가기
개발/React

리액트 - 게으른 초기화로 useState 초기화하기 (Lazy Initialization for useState)

by 피로물든딸기 2024. 4. 7.
반응형

리액트 전체 링크

 

참고

- https://legacy.reactjs.org/docs/hooks-reference.html#lazy-initial-state

- React.memo, useMemo, useCallback으로 최적화하기

 

이전 글에서 상태 변경에 의해 컴포넌트가 매번 렌더링 될 때 메모이제이션을 이용해 렌더링을 최적화하였다.

 

비슷한 최적화로 useState게으른 초기화(Lazy Initialization)를 사용할 수 있다.

useState의 초기화에서 함수를 사용하고 있는 경우를 살펴보자.

 

만약 value0getInitValue 함수로 값을 초기화한다고 가정하자.

const getInitValue = () => {
  console.log("getInitValue");
  return "";
}

const MemoTest = () => {
  const [value0, setValue0] = useState(getInitValue());

 

그럼 컴포넌트가 다시 렌더링 될 때 마다 아래와 같이 getInitValue 로그가 출력되는 것을 알 수 있다.

렌더링에 의해 함수 컴포넌트( = useState 값)의 함수가 같이 실행되기 때문이다.

 

게으른 초기화는 단지 함수를 실행해 값을 반환하도록 수정만 하면 된다.

const [value0, setValue0] = useState(() => getInitValue());
// or const [value0, setValue0] = useState(() => { return getInitValue(); });

 

이제 getInitValue가 실행되지 않는다.

 

만약 getInitValue비용이 꽤 큰 작업이라면, 게으른 초기화를 사용하는 것이 좋다.

 

전체 코드는 다음과 같다.

import React, { useCallback, useMemo, useState } from "react";

const MySpan = ({ input }) => {
  console.log("MySpan is Rendered...");
  return <span>input 0 : {input}</span>;
};

const MySpanMemo = React.memo(MySpan);

const getInitValue = () => {
  console.log("getInitValue");
  return "";
}

const MemoTest = () => {
  const [value0, setValue0] = useState(() => { return getInitValue(); });
  const [value1, setValue1] = useState("");
  const [value2, setValue2] = useState("");
  const [number, setNumber] = useState(0);

  const MySpanUseMemo = useMemo(() => <MySpan input={value0} />, [value0]);

  const handleChange0 = (e) => {
    console.log("change 0");
    let input = e.target.value;
    setValue0(input);
  };

  const handleChange1 = (e) => {
    console.log("change 1");
    let input = e.target.value;
    setValue1(input);
  };

  const handleChange2 = (e) => {
    console.log("change 2");
    let input = e.target.value;
    setValue2(input);
  };

  const upperCase = (input) => {
    console.log("upper case", input);
    return input.toUpperCase();
  };

  const lowerCase = (input) => {
    console.log("lower case", input);
    return input.toLowerCase();
  };

  const upperInput = useMemo(() => upperCase(value1), [value1]);
  const lowerInput = lowerCase(value2);
  const plusNumber = useCallback(() => {
    console.log("plus number", number);
    setNumber((prev) => prev + 1);
  }, []);

  return (
    <div
      style={{
        margin: 5,
        display: "flex",
        flexDirection: "column",
        width: 200,
      }}
    >
      <input
        type="text"
        value={value0}
        onChange={handleChange0}
        placeholder="value 0"
      />
      <input
        type="text"
        value={value1}
        onChange={handleChange1}
        placeholder="value 1"
      />
      <input
        type="text"
        value={value2}
        onChange={handleChange2}
        placeholder="value 2"
      />
      <MySpanMemo input={value0} />
      {MySpanUseMemo}
      <span>input 1 : {upperInput}</span>
      <span>input 2 : {lowerInput}</span>
      <button onClick={plusNumber}>+</button>
      <span>number : {number}</span>
    </div>
  );
};

export default MemoTest;
반응형

댓글