본문으로 바로가기

프로젝트를 하며 localStorage를 이용하다 보니 저장된 값을 불러와야 해 초기 값 설정을 getStorage()라는 함수를 이용하게 되었습니다.

const [medalList, setMedalList] = useState(getStorage(key) || []);

 

export const setStorage = (key, value) => {
    try {
        console.log('setStorage 실행!');
        localStorage.setItem(key, JSON.stringify(value));
    } catch (err) {
        console.error('Failed setStorage : ', err);
    }
};

 

하지만 문제는, 분명 초기에 값을 설정하면 그 역할을 다 한 줄 알았던 getStorage 함수가 렌더링이 될 때마다 계속 실행된다는 점이었습니다.

 

 

그렇다면 맨 처음 렌더링 때 한번만 setStorage를 실행하는 방법은 없을까요?

 

일반적으로 useState는 초기 상태 값을 직접 전달받습니다.

 

예를 들어 카운터라고 할 경우 초기 값이 0이겠죠?

const [count, setCount] = useState(0);

 

이렇게 초기 상태를 설정할 때 0이라는 값 하나라면 매번 렌더링 시 수행해도 상관이 없을 것입니다.

 

하지만 초기화 과정이 복잡하고 비용이 많이 드는 경우에는 어떨까요?

카운터의 초기 값을 설정할 때 복잡한 작업이 있다고 가정해 봅시다.

const initializeFunc = () => {
    console.log('복잡한 작업');
    return 0;
}

const Test = () => {
    const [count, setCount] = useState(initializeFunc());

    const increase = () => {
        setCount(count + 1);
    }
    
    return (
        <div>
            {count}
            <button onClick={(increase)}>increase!</button>
        </div>
    );
};

 

increase 버튼을 누르면 무슨 일이 발생할까요?

 

이렇게 count가 바뀔 때마다 렌더링이 되므로 복잡한 작업을 계속해서 수행하게 됩니다. 어떻게 해결할 수 있을까요?

 

바로 지연 초기화(Lazy Initialization)을 이용하는 것입니다!

 

useState에 초기 상태를 설정할 때, 계산 비용이 높은 작업을 매번 렌더링 시마다 수행하는 것은 비효율적입니다.

이를 개선하기 위해, useState는 초기 상태를 반환하는 함수를 인수로 받을 수 있습니다.

이 함수는 컴포넌트의 최초 렌더링 시에만 호출되어 초기 상태를 설정하며, 이후 렌더링에서는 호출되지 않습니다.

 

const [count, setCount] = useState(initializeFunc);

 

useState의 인자로 함수를 실행시키는 것이 아닌 함수명만 전달해 봅시다.

 

이렇게 렌더링이 반복되어도 intializeFunc가 최초 한 번만 실행되는 것을 알 수 있습니다.

 

그럼 프로젝트에 적용해봅시다.

const [medalList, setMedalList] = useState(() => {
        return getStorage(key) || [];
    });

 

getStorage에 인자를 전달해주어야 하니 화살표 함수로 묶어서 함수를 useState의 인자로 넣어줍니다.

 

 

이렇게 state가 바뀌어도 getStorage 함수는 한번만 실행되는 것을 알 수 있습니다!

물론 아직 하는 프로젝트에서는 getStorage가 계속 실행되어도 문제가 없겠지만 만약에 규모가 큰 프로젝트였다면....?

성능 최적화를 위해 지연 초기화를 항상 기억하고 있어야겠습니다!