6. Hook - 2

맨날·2021년 5월 22일
0

useMemo

useMemo를 사용하면 연산을 최적화할 수 있습니다. 두번째 파라미터로 전달된 의존성 값이 변경될때만 전달 된 함수를 실행하게 됩니다.

아래와 같이 코드를 작성 후 input 창에 값을 입력할때마다 콘솔이 찍히는 것을 확인할 수 있습니다.

const getAverage = numbers => {
  console.log('평균값 계산중..');
  if (number.length === 0) return 0;
  const sum = numbers.reduce((a, b) => a + b);
  return sum / numbers.length;
}

const Average = () => {
  const [number, setNumber] = useState('');
  const [list, setList] = useState([]);
  
  const onChange = e => setNumber(e.target.value);
  const onInsert = () => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber('');
  }
  
  return (
    <input value={number} onChange={onChange} />
    <button onClick={onInsert}>등록</button>
    <ul>
      {list.map((value, index) => (
        <li key={index}>{value}</li>
      ))}
    </ul>
    <div>
      <b>평균값:</b>{getAverage}
    </div>
  )
}

useMemo를 이용해서 의존 상태값이 변할때만 함수를 호출하도록 변경해보겠습니다.

(...)

const Average = () => {
  (...)
  
  const avg = useMemo(() => getAverage(list), [list]); 
   
  return (
    (...)
    <div>
      <b>평균값:</b>{avg}
    </div>
  )
} 

이제는 input에 값을 입력하여도 콘솔이 찍히지 않고, list가 변할때만 콘솔이 찍히는 걸 확인할 수 있습니다.

useCallback

useCallbackuseMemo와 같이 메모이제이션 기능을 활용하여, 최적화하는데 사용합니다. useCallback을 사용하면 의존성 값이 변경될때만 이벤트 핸들러 함수를 생성할 수 있습니다.

const Counter = () => {
  const [count, setCount] = useState(0);
  
  const onIncrease = () => setCount(count + 1);
  const onDecrease = () => setCount(count - 1);
  
  return (
    <div>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
      <p>{count}</p>
    </div>
  )
}

위와 같은 카운터 컴포넌트가 존재합니다. 현재는 렌더링 될때마다 이벤트 핸들러 함수가 새롭게 생성이 됩니다. 아래와 같이 변경하도록 하겠습니다.

const Counter = () => {
  const [count, setCount] = useState(0);
  
  const onIncrease = useCallback(
    () => setCount(count + 1),
    [count]
  );
  const onDecrease = useCallback(
    () => setCount(count - 1),
    [count]
  );
  
  return (
    <div>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
      <p>{count}</p>
    </div>
  )
}

useCallback(fn, deps)는 useMemo(() => fn, deps)와 동일합니다.

useCallback 정리

  1. 두번째 파라미터로 배열을 넘겨주지 않으면 렌더링시마다 함수를 생성합니다.
  2. 두번째 파라미터로 빈배열을 넘겨주면 최초에 1회에 한해서만 함수를 생성합니다.
  3. 두번째 파라미터로 의존성 값을 넘겨주면 해당 의존성 값이 변경될때만 함수를 생성합니다.

함수내부에서 의존성 값을 사용한다면 두번째 파라미터의 배열에 추가해주어야 합니다.
그렇지 않으면 함수를 새롭게 생성하지 않기때문에, 현재값이 아닌 함수 생성 당시의 값을 참조하게 될 것입니다.

useRef

useRef로 반환 된 객체를 이용해서 컴포넌트의 ref 속성을 설정할 수 있습니다. 그러면 ref 객체의 .current 속성에 DOM 노드를 설정해 줍니다.

const Input = () => {
  const [value, setValue] = useState('');
  const [list, setList] = useState([]);
  const inputEl = useRef(null);
  
  const onChange = e => setValue(e.target.value);
  const onClick = () => {
    const nextList = list.concat(value);
    setList(nextList);
    setValue('');
    inputEl.current.focus();
  }
  
  return (
    <div>
      <input value={value} onChange={onChange} />
      <button onClick={onClick}>등록</button>
    </div>
  )
}

useRef를 사용하여 ref를 설장하면 엘리먼트에 직접 접근을 할 수 있습니다. 스크롤이벤트나, focus 등과 같이 엘리먼트에 직접 접근해야 하는 경우에 useRef를 사용할 수 있습니다.

로컬 변수 사용하기

로컬 변수를 사용할 때도 useRef를 사용할 수 있습니다. ref 객체의 생명주기는 컴포넌트의 생명주기와 동일하기 때문에 이를 활용하여 로컬 변수를 사용할 수 있습니다.

const RefSample = () => {
  const id = useRef(1);
  const setId = (n) => {
    id.current = n;
  }
  const printId = () => {
    console.log(id.current);
  }
  
  return (
    <div>
      refsample
    </div>
  )
}

.current 값은 변경이 되어도 리렌더링 되지 않습니다.

최적화 Hook

useMemo, useCallback 와 같은 훅은 최적화를 할 때 사용이 되는 훅입니다. 하지만 잘못 사용하였을 경우 해당 훅들을 사용했을때보다 더 많은 비용을 초래할 경우가 생길 수 있습니다. 대부분의 경우에는 이러한 최적화 훅들을 사용할 필요가 없습니다.

0개의 댓글