본문 바로가기
Front/React

[React] Hooks - useMemo(), useCallback(), useRef()

by 오엥?은 2023. 4. 18.
반응형

 

③ useMemo()

: Memoizes value 를 리턴하는 Hook

 

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

의존성 배열에 들어있는 변수가 변했을 경우에만 새로 create 함수를 호출하여 결과값을 반환하며, 그렇지 않은 경우에는 기존 함수의 결과값을 그대로 반환한다.

 

useMemo() Hook 을 사용하면 component 가 다시 렌더링 될 때마다 연산량이 높은 작업을 반복하는 것을 피할 수 있다.

-> 빠른 렌더링 속도를 얻을 수 있다.

 

❌ useMemo() 로 전달된 함수는 렌더링이 일어나는 동안 실행된다.

 - 렌더링이 일어나는 동안 실행돼서는 안 될 작업을 useMemo 함수에 넣으면 안 된다.

     : ex) useEffect 에서 일어나야 할 side effect, 서버에서 데이터를 받아오거나 수동으로 DOM 을 변경하는 작업 등

 

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

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

 

const memoizedValue = useMemo (
    () => {
    	return computeExpensiveValue(a, b);
    },
    []
);

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

 

 

 

④ useCallback()

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

-> 컴포넌트가 렌더링 될 때마다 함수를 새로 정의하는 것이 아니라, 의존성 배열의 값이 바뀌는 경우에만 함수를 새로 정의해서 return 해 주는 것이다.

 

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

useMemo() Hook 과 마찬가지로 의존성 배열을 파라미터로 받는다. useCallback() 에서는 파라미터로 받는 이 함수를 callback 이라고 부른다. 의존성 배열에 있는 변수 중 하나라도 변경되면, memorization 된 callback 함수를 반환한다. 의존성 배열에 따라 memoized 값을 반환한다는 점에서는 useMemo() Hook 과 완전히 동일하다.

 

useCallback (함수, 의존성 배열);

useMemo(() => 함수, 의존성 배열);

따라서 의 두 줄의 코드는 동일한 역할을 한다.

 

 

  • useCallback() 장점
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>
    );
}

useCallback Hook 을 사용하면 특정 변수의 값이 변한 경우에만 함수를 다시 정의하기 때문에 함수가 다시 정의되지 않는 경우에는 자식 컴포넌트도 재렌더링이 일어나지 않는다. 이 경우에는 의존성 배열에 빈 배열이 들어갔기 때문에 컴포넌트가 처음 mount 되는 시점에만 함수가 정의되고, 이 후에는 다시 정의되지 않으며 자식 컴포넌트도 불필요하게 재렌더링이 일어나지 않게 된다.

 

 

 

⑤ useRef()

 : Reference(특정 컴포넌트에 접근할 수 있는 객체)를 사용하기 위한 Hook

 refObject.current (현재 참조하고 있는 Element)

 

  • useRef() 사용법
const refContainer = useref(초깃값);

useRef() Hook 은 변경 가능한 current 라는 속성을 가진 하나의 상자라고 생각하면 된다.

 

function TextInputWithFocusButton(props) {
    cosnt inputElem = useRef(null);
    
    const onButtonClick = () => {
    	// `current` 는 마운트된 input element 를 가리킴
        inputElem.current.focus();
    };
    
    return (
    	<>
            <input ref={iputElem} type="text" />
            <button onClick={onButtonClick}>
            	Focus the input
            </button>
        </>
    );
}

useRef() Hook 은 내부의 데이터가 변경되었을 때 별도로 알리지 않는다. 그래서 current 속성을 변경한다고 해서 재렌더링이 일어나지는 않는다.

 

  • Callback ref
function MeasureExample(props) {
    const [height, setHeight] = useState(0);
    
    const measuredRef = useCallback(node => {
    	if (node !== null) {
            setHeight(node.getBoundingClientReact().height);
        } 
    }, []);
    
    return (
    	<>
            <h1 ref={measureedRef}>안녕, 리액트</h1>
            <h2>위 헤더의 높이는 {Math.round(height)}px 입니다.</h2>
        </>
    );
}

위 코드는 reference 를 위해서 useRef() Hook 을 사용하지 않고, useCallback() Hook 을 사용하는 Callback ref 방식을 사용했다. useRef() Hook 을 사용하게 되면 reference 객체가 current 속성이 변경되었는지를 따로 알려주지 않기 때문이다.하지만 Callback ref 방식을 사용하게 되면, 자식 컴포넌트가 변경되었을 때 알림을 받을 수 있고 이를 통해 다른 정보들을 업데이트할 수 있다.

 

위 코드에서는 h1 의 높이 값을 매번 업데이트하고 있다. useCallback() Hook 의 의존성 배열로 비어있는 배열을 넣었는데, 이렇게 하면 h1 태그가 mount / unmount 될 때만 Callback 함수가 호출되며, 재렌더링이 일어날 때는 호출되지 않는다.

 

 

 

반응형