Dev/React

React Hook 정리

takeU 2023. 9. 25. 15:26
반응형

React Hook 정리

 

개발하면서 끊임없이 훅으로 코드를 짜면서도 잘 모르고 사용하는 부분이 많아 정리를 해볼 필요가 있다 생각이 들음.

꼭 필요한 내용들 위주로 작성하려 함.

 

React Hook 이란?

우선 Hook이 도입되기 이전의 방식인 Class형 컴포넌트의 문제점은 다음과 같다

  1. 생명주기 메소드를 사용할 때, 해당 메소드에 설계 의도 이외의 코드가 들어가는 상황이 빈번해지고, 이는 버그를 유발하고 무결성을 해치게 됨.
  2. this 는 재사용성과 구성을 복잡하게 함.

이러한 문제를 안고 React 16.8 버전에 추가된 React Hook의 특징

  1. 컴포넌트로부터 상태 관련 로직을 추상화 할 수 있다.
  2. 계층의 변화 없이 상태 관련 로직을 재사용할 수 있도록 도와준다.
  3. Hook을 도입했지만, Class를 제거할 계획은 없다는 말의 의도는 잘 모르겠음. 귀찮은건지..

크게 값을 다루는 State Hook과 side-effect를 다루는 Effect Hook으로 구분지어 정의

 

React Hook의 종류

 

useState

const [counter, setCounter] = useState(0)
// state, setState / initialState의 구조

state의 immutable한 특징에 의해, setState는 새로운 값이 할당되는 것이 아닌 값을 업데이트하는 비동기 방식으로 동작한다.

일반적인 원시값은 값으로 업데이트해도 상관이 없지만, 객체같은 경우는 funtional updates를 해야이전 state를 받아 새롭게 업데이트가 가능함.

다만 객체의 depth가 늘어나면, 내부의 객체는 업데이트가 되지 않음 (shallow merge)

const [state, setState] = useState({});
setState(prevState => {
  // Object.assign would also work
  return {...prevState, ...updatedValues};
});

 

useEffect

useEffect(()=>{
  setCounterSquared(counter ** 2)
}, [counter])
// effect, dependency의 구조

두 번째 인자인 dependency가 변경될 경우 effect가 실행되는 구조

dependency가 빈 배열인 경우 첫 렌더링 시 한번 실행됨.

dependency를 넣지 않으면, 모든 변수가 수정될 때 마다 함수가 실행됨.

dependency를 넣더라도 처음 렌더링 시 실행되기 때문에, 이를 방지하기 위해서는 effect 안에 조건문을 넣어줘야 함.

dependency가 2-depth 이상의 객체나 배열인 경우 감지하지 못함

첫 번째 인자에서 state나 props를 사용하면 dependency에 추가해줘야 최신 상태로 유지가 가능

useEffect는 함수나 조건문 안에 혹은 return문 아래에 위치하면 안됨 - react는 각각의 useEffect 훅을 실행 순서로 기억하고 관리하기 때문

 

useLayoutEffect

브라우저가 화면을 다시 채우기 전에 실행되는 버전의 useEffect (문법 동일)

렌더링 후, layout과 paint 전에 동기적으로 실행됨

헤더의 높이를 측정해 main component의 높이를 calc로 할당해 주는 경우에 사용하는 식으로 사용할 수 있음

성능 모니터링 기능을 사용할 때 유용

 

useRef

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

useRef()가 순수 자바스크립트 객체를 생성 ({current: …})

current 프로퍼티를 변형하는 것이 리렌더링을 발생시키지는 않음

이는 시각적 출력에 영향을 미치지 않는 정보를 저장하는데 적합

 

useMemo

const cachedValue = useMemo(calculateValue, dependencies)

리렌더링 사이의 계산 결과를 캐시할 수 있는 React 훅

인자 1 - 순수함수이며, 인자가 없어야 함

인자 2의 의존성을 비교해, 변경되지 않았으면 이전에 계산한 값을 반환해 줌

객체 타입은 매번주소가 바뀌어 useEffect에 의존성을 넣더라도 리렌더가 되기 때문에 이런 경우에 useMemo를 사용해야 함

console.time으로 측정 시 1ms 이상 시간이 소요되면 메모하는 것이 좋음

 

useCallback

const cachedFn = useCallback(fn, dependencies)

리렌더링 사이에 함수 정의를 캐시할 수 있는 React 훅

인자 1 - 캐시하려는 함수이며, 어떤 인자도 받을 수 있고 어떤 값이라도 반환할 수 있음

인자 2의 의존성을 비교해, 변경되지 않았으면 이전에 저장된 함수 fn을 반환

 

useMemo vs useCallback

// 간소화된 구현체 (React 내부)
function useCallback(fn, dependencies) {
  return useMemo(() => fn, dependencies);
}

useCallback은 함수를 반환, useMemo는 값을 반환

 

사용해야하는 경우

함수 자체가 매우 복잡하거나, 다시 계산하는데 비용이 많이 드는 경우

map, filter 등을 사용하는 경우

부모가 리렌더링 될 때 자식까지 렌더링 전파를 막고 싶을 때

 

쓰고보니 별로 쓴게없네..