처음 만난 리액트(React) : section 7. Hooks - 2 useMemo, useCallback, useRef

꿀돼질래·2022년 8월 24일
0
post-thumbnail

💡 useMemo, useCallback, useRef

useMemo()

Memoized value를 리턴하는 Hook

useMemo() 사용법

constmemoizedValue = useMemo (
() => {
// 연산량이 높은 작업을 수행하여 결과를 반환
return computeExpensiveValue (의존성 변수1, 의존성 변수2);
},
[의존성 변수1, 의존성 변수2]
);

  • 빠른 렌더링 속도
    • 컴포넌트가 렌더링 될 때 마다 연산량이 높은 작업을 반복하는 것을 피할 수 있음

❕ useMemo로 전달된 함수는 렌더링이 될 때만 실행
❕ 렌더링이 일어나는 동안 실행되서 안되는 작업을 넣으면 안됨 (useEffect Hook에서 실행되는 sideEffect)

의존성 배열을 넣지 않을 경우, 매 렌더링마다 함수가 실행

const memoizedValue = useMemo(
	() => computeExpensiveValue(a,b)
);

의존성 배열이 빈 배열일 경우, 컴포넌트 마운트 시에만 호출

const memoizedValue = useMemo(
	() => {
    	return computeExpensiveValue(a, b);
    },
    []
);
// mount 이후에 값의 변화가 없음
// mount 시점에서 한 번 값을 계산할 필요가 있을 경우에 사용
// 대부분 useMemo Hook에 의존성 배열의 변수들을 넣고 해당 변수들 값의 변화에 따라 새로 값을 계산할 경우에 사용

Memoization

최적화를 위해 사용하는 개념

  • 연산량이 많이 드는 함수의 호출 결과를 저장
    • 같은 입력값으로 함수 호출 시 새로 호출하지 않고 이전에 저장한 호출 결과를 바로 반환
    • 함수 호출 결과를 받기까지 시간 절약, 불필요한 중복 연산을 하지 않아 컴퓨터의 자원을 적게 씀

useCallback()

useMemo() Hook과 유사하지만 값이 아닌 함수를 반환

  • 컴포넌트가 렌더링될 때마다 매번 함수를 정의하는 것이 아니라 의존성 값이 바뀐 경우에 함수를 새로 정의해 리턴

useCallback() 사용법

const memoizedCallback = useCallback(
() => {
doSomething(의존성 변수1, 의존성 변수2);
},
[의존성 변수1, 의존성 변수2]
);

  • 의존성 배열에 있는 변수 중 하나라도 변경되면 memoization된 callBack 함수를 반환

동일한 역할을 하는 두 줄의 코드

useCallback(함수, 의존성 배열);
useMemo(() => 함수, 의존성 배열);
  • useCallback Hook을 사용하지않고 컴포넌트 내에 함수를 정의하면 매번 렌더링마다 함수 새로 정의

❕ useCallback Hook을 사용하여 특정 변수의 값이 변한 경우에만 다시 정의, 불필요한 반복 작업 줄이기

useCallback Hook을 사용하지 않고 컴포낸트 내에 정의

// 자식Component Props에 넘겨 사용
// 부모Component가 렌더링될 때마다 매번 자식Component도 렌더링
import { useState } from "react";

function ParentComponent(props) {
  const [count, setCount] = useState(0);
  
  // 재렌더링 될 때마다 매번 함수가 새로 정의
  const handleClick = (event) => {
    // 클릭 이벤트 처리
  };
  
  return (
    	<div>
    		<button
    			onClick={() => {
    				setCount(count + 1);
 				}}
			>
              	{count}
			</button>

			<ChildComponent handleClick={handleClick} />
        </div>
		);
}

useCallback Hook 사용

// 특정 변수의 값이 변한 경우에만 함수를 다시 정의
// 함수가 다시 정의되지 않은 경우에 자식 Component도 재렌더링되지 않음
// 의존성 배열에 빈배열로 Component가 처음 mount되는 시점에 함수가 정의, 이후에 정의되지 않음
// 자식Component도 불필요한 재렌더링이 일어나지 않음
import { useState, useCallback } from "react";

function ParentComponent(props) {
	const [count, setCount] = useState(0);
    
    // 컴포넌트가 마운트 될 때만 함수가 정의
    const handleClick = useCallback((event) => {
    	// 클릭 이벤트 처리
    }, []);
    
    return (
      	<div>
      		<button
      			onClick={() => {
      				setCount(count + 1);
    			}}
			>
              	{count}
			</button>

			<ChildComponent handleClick={handleClick} />
            </div>
		);
}

useRef()

변경 가능한 current 속성을 가진 상자

Reference를 사용하기 위한 Hook
Reference 객체를 반환

useRef() 사용법

const refContainer = useRef(초기값);

  • 초기값이 null이면 current값이 null인 reference 객체 반환
  • 반환된 reference 객체는 Component lifetime 전체에 걸쳐 유지
  • Component가 mount 해제 전까지 유지
  • Class에 instance 필드를 사용하는 것과 유사하게 다양한 변수 저장 가능
    • 일반적인 자바스크립트 객체를 반환

Reference

  • 특정 컴포넌트에 접근할 수 있는 객체

refObject.current

  • current 속성
    • 현재 참조하고 있는 Element

useRef Hook을 사용하여 버튼 클릭시 input에 포커스

function TextInputWithFocusButton(props) {
  	// 초기값 null, 결과를 반환, inputElem이라는 reference객체를 input태그에 넣음
	const inputElem = useRef(null);
  
  	const onButtonClick = () => {
      // `current`는 마운트된 input element를 가리킴
      // inputElem.current를 통해 실제 element에 접근해 focus 함수 호출
      inputElem.current.focus();
    };
  
  	return (
      	<>
      		<input ref={inputElem} type="text" />
      		<button onClick={onButtonClick}>
              	Focus the input
            </button>
		</>
	);
}

DOM에 접근하기 위한 Ref 속성

<div ref={myRef} />
  • 로드가 변경될 때마다 myRef에 current 속성에 현재 해당되는 DOM 로드 저장

직접 current 속성에 포함된 자바스크립트 객체를 만들어도 되는가?

  • 목적 달성은 가능하나
    • useRef Hook을 사용하는 것
      • 매번 렌더링될 때마다 항상 같은 reference 객체를 반환
    • 직접 current 속성에 포함된 모양의 객체를 만들어 사용
      • 재렌더링이 일어나지 않음, DOM로드가 연결 혹은 분리되었을 때 Callbackref를 사용해야 함

❕ useRef() Hook은 내부의 데이터가 변경되었을 때 별도로 알리지 않음

Callback ref

  • Reference를 위해서 useRef Hook을 사용하지 않고 useCallback Hook 사용 하는 방식
function MeasureExample(props) {
	const [height, setHeight] = useState(0);
    
    const measuredRef = useCallback(node => {
    	if (node !== null) {
        	setHeight(node.getBoundingClientReact().height);
        }
   }, []);
   
   return (
   		<>	
        	<h1 ref={measureddRef}>안녕, 리액트</h1>
            <h2>위 헤더의 높이는 {Math.round(height)}px 입니다.</h2>
        </>
   );
}
// useCallback ref방식을 사용 시 자식Component가 변경되었을 때 알림을 받음
// 이를 통해 다른 정보를 업데이트
// h1의 높이 값을 매번 업데이트
// useCallback Hook의 의존성 배열로 비여있는 배열, h1태그가 mount,unmount될 때나 callBack함수가 호출되며 재렌더링될 때는 호출되지 않음

0개의 댓글