Hook의 종류 - 2
useMemo()
Memoized value를 리턴하는 Hook
Memoization
비용이 높은 함수의 호출 결과를 저장해 뒀다가, 같은 입력값으로 함수를 호출하면 저장해둔 호출 결과를 바로 반환한다.
➰ Memo를 해두었다가 나중에 다시 사용하는 것!
- 속도를 향상하고, 불필요한 중복 연산을 제거할 수 있다.
- Memoized Value : Memoization된 결과값
사용법
const memoizedValue = useMemo(
() => {
// 연산량이 높은 작업을 수행하여 결과를 반환
return computeExpensiveValue(의존성 변수1, 의존성 변수2);
},
[의존성 변수1, 의존성 변수2]
);
2개의 파라미터를 갖는다.
- memoization 해줄 값을 계산해서 리턴해주는 함수 (callback)
⏩ useMemo가 리턴하는 값, memoizedValue - 의존성 배열
의존성 배열에 있는 변수가 업데이트 됐을 경우에만,
- callback을 호출하여
- memoization된 값을 업데이트(re-memoization),
- 결괏값을 반환하고
그렇지 않을 경우 기존 함수의 결과값을 그대로 반환한다.
useMemo()로 전달된 함수는 렌더링이 일어나는 동안 실행된다.
⏩ 렌더링이 일어나는 동안 실행되어선 안 되는 작업을 useMemo()에 넣어서는 안 된다.
- 예를 들면, 'Side Effect' ✅ useEffect()에서 실행되어야 한다.
➰ 서버에서 데이터를 받아오거나 수동으로 돔을 변경하는 작업 등
📌 예제1-1. useMemo() - 의존성 배열 생략
const memoizedValue = useMemo(
() => computeExpensiveValue(a,b)
);
의존성 배열을 넣지 않으면, 매 렌더링마다 함수가 실행
✅ useMemo()에서 배열을 넣지 않는 것은 아무 의미 없다.
📌 예제1-2. useMemo() - 의존성 배열에 빈 배열 할당
const memoizedValue = useMemo(
() => {
return computeExpensiveValue(a,b)
}, []
);
- 의존성 배열이 빈 배열일 경우, 컴포넌트가 마운트 될 때만 callback이 호출
⏩ 마운트 이후에는 값이 변경되지 않음
- 마운트 시점에만 값을 계산할 필요가 있을 경우에 이렇게 사용
- 하지만 대부분의 경우, 의존성 배열에 값이들어 간다.
useCallback()
useMemo()와 유사하지만, 값이 아닌 함수를 반환한다.
사용법
const memoizedCallback = useCallback(
() => {
doSomething(의존성 변수1, 의존성 변수2);
},
[의존성 변수1, 의존성 변수2],
);
2개의 파라미터를 갖는다.
- callback
- 의존성 배열
컴포넌트가 렌더링 될 때마다 함수를 새로 정의하는 것이 아니라, 의존성 배열이 바뀐 경우에만 함수를 새로 정의한다.
의존성 배열에 있는 변수 중 하나라도 변경되면 memoization 된 callback 반환한다.
Summary
아래 두 코드는 동일한 역할을 한다.
useCallback(함수, 의존성 배열)
useMemo(() => 함수, 의존성 배열)
코드로 이해하기
useCallback()를 사용하지 않고 컴포넌트 내에 함수를 정의하면, 렌더링이 일어날 때마다 새로 함수가 정의된다.
✅ useCallback()을 사용하여 특정 변수의 값이 변한 경우에만 함수를 다시 정의하도록 한다.
📌 예제2-1. useCallback() 사용하지 않은 경우
import React, { useState } 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>
)
}
📌 예제2-1. useCallback() 사용한 경우
import React, { 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>
)
}
- 특정 변수의 값이 변한 경우에만 함수를 다시 정의
⏩ 함수가 다시 정의되지 않는 경우에는, 자식 컴포넌트(ChildComponent)도 재렌더링이 일어나지 않는다. - 의존성 배열이 빈 배열이므로, 컴포넌트가 처음 마운트 되는 시점에만 함수가 정의된다.
useRef()
Reference를 사용하기 위한 Hook으로, Reference 객체를 반환한다.
- Reference : 특정 컴포넌트에 접근할 수 있는 객체
refObject.current
- current : Property of refObject
- 현재 참조하고 있는 Element를 나타낸다.
사용법
const refContainer = useRef(초깃값)
.current의 값이 (초깃값)인 ref 객체를 반환한다.
반환된 ref 객체는 current의 Lifecycle 전체에 걸쳐서 유지된다.
⏩ 즉, 컴포넌트가 마운트 해제되기 전까지는 계속 유지된다.
본질적으로 useRef는 .current 프로퍼티에 변경 가능한 값을 담고 있는 "상자"와 같습니다.
- 리액트 공식문서
📌예제3. useRef()
function TextInputWithFocusButton(props) {
const inputElem = useRef(null);
const onButtonClick = () => {
// current는 마운트 된 input element를 가리킴
inputElem.current.focus();
}
return (
<>
<input ref={inputElem} type="text"/>
<button onClick={onButtonClick}>
Focus the input
</button>
</>
)
}
- 버튼 클릭 시 input에 포커스
- 작동 원리
- useRef() 를 사용하여 Ref 객체를 만들고,
- 이 객체를 우리가 선택하고 싶은 DOM 에 ref 값으로 설정해준다.
- 그러면, Ref 객체의 .current 값은 우리가 원하는 DOM 을 가르키게 된다.
useRef()는 내부의 데이터가 변경되어도 따로 알리지 않는다.
⏩ 즉, current 속성을 바꾼다고 해서 다시 렌더링이 일어나진 않는다.
✅ Ref에 DOM 노드가 연결/분리 되었을 경우, 어떤 코드를 실행하고 싶다면 Callback ref 사용한다.
Callback ref
ref가 다른 노드에 연결될 때 마다 callback을 호출한다.
✅ ref 에 useRef로 반환된 값을 넘기는게 아니라 함수를 넘긴다.
📌 예제4. Callback ref
function MeasureExample(props) {
const [ height, setHeight ] = useState(0);
const measuredRef = useCallback(node => {
if(node!== null){
setHeight(node.getBoundinClientRect().height);
}
}, []);
return (
<>
<h1 ref={measuredRef}>안녕, 리액트</h1>
<h2>위 헤더의 높이는 {Math.round(height)}px 입니다.</h2>
</>
)
}
- Ref를 위해서 useRef()를 사용하지 않고, useCallback() 사용✅ ref attribute에 DOM이 아닌 함수를 할당한다.
- 자식 컴포넌트가 변경되었을 때 알림을 받을 수 있다.
- 의존성 배열에 빈 배열 할당 ⏩ h1 태그가 mount/unmount할 때만 callback 호출
🚀 참고
- 처음 만난 리액트(React) , 소플 - 섹션7. Hooks
➰ 더 공부할 것 : 영상보고 정리
'React' 카테고리의 다른 글
[React] Composition VS. Inheritance - Containment, Specialization (0) | 2023.01.06 |
---|---|
[React] Hook의 규칙과 Custom Hook - 커스텀 훅 특징 및 사용법 (0) | 2022.12.30 |
[React] React Hook의 개념과 종류 - useState(), useEffect() (0) | 2022.12.29 |
[React] 리액트 Form의 특징과 종류 - 제어 컴포넌트 (0) | 2022.12.29 |
[React] List와 key의 개념과 컴포넌트 렌더링 - map(), filter() (0) | 2022.12.29 |
댓글