// 리액트를 다루는 기술 8장
지난 포스팅에 이어 작성해유
: 함수형 컴포넌트 내부에서 발생하는 연산을 최적화할 수 있는 Hook
useMemo는 렌더링하는 과정에서 특정 값이 바뀌었을 때만 연산을 실행하고, 원하는 값이 바뀌지 않았다면 이전에 연산했던 결과를 다시 사용합니다.
기본 형태
const a = useMemo(function, deps)
예시로 숫자들의 평균을 보여주는 함수형 컴포넌트를 일단 useState를 사용하여 작성!
import React, {useState} from 'react';
const getAverage = numbers => {
console.log('평균값 계산 중...');
if (numbers.length === 0) return 0;
const sum = numbers.reduce((a,b) => a+b);
// a는 누적값 b는 numbers라는 배열에 요소
// 즉, numbers에 있는 요소들을 다 더한 값을 a에 계속 더하고 sum이라는 변수에 넣음
return sum/ numbers.length;
}
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState('');
const onChange = e => {
setNumber(e.target.value);
};
const onInsert = e => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber('');
};
return (
<div>
<input value = {number} onChange = {onChange} />
<button onClick = {onInsert}> 등록 </button>
<ul>
{list.map((value, index) => (
<li key = {index}> {value} </li>
))}
</ul>
<div>
<b>평균값: </b> {getAverage(list)}
</div>
</div>
)
}
export default Average;
위의 코드를 useMemoe를 사용하면 인풋 내용이 바뀔 때마다 평균값을 다시 계산하지 않도록 즉, 렌더링할 때마다 계산하지 않도록 할 수 있음!
( 즉, useMemo를 사용하기 전에는 버튼을 누르기 전 숫자를 입력하기만 해도 함수를 불러오지만 useMemo를 사용한 후에는 버튼을 눌러야 함수를 불러옴 ) 근데 이건 onChange를 안 쓰면 되지 않나?
...
const Average = () => {
...
const avg = useMemo(() => getAverage(list), [list]);
return (
...
<b>평균값: </b> {avg}
...
)
}
export default Average;
useMemo와 상당히 비슷한 함수!!
const a = useCallback(function, [deps]);
...
const Average = () => {
...
const onChange = useCallback(e => {
setNumber(e.target.value);
}, []); // 컴포넌트가 처음 렌더링될 때만 함수 생성
const onInsert = useCallback(() => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber('');
}, [number, list]); // number 혹은 list가 바뀌었을 때만 함수 생성
...
}
export default Average;
: 숫자, 문자열, 객체처럼 일반 값을 재사용하려면 useMemo
: 함수를 재사용하려면 useCallback
이 차이점을 제외하곤 차이점이 거의 존재하지 않음
참고 블로그
https://www.zigae.com/react-memo/
리액트 useCallback, useMemo 언제 사용 할까?
본글은 useCallback, useMemo에 대해 설명하는 글이 아님을 알린다.
www.zigae.com
: 함수형 컴포넌트에서 ref를 쉽게 사용할 수 있도록 해줌
: html에서 DOM요소에 이름을 달 때 id라는 고유값을 사용하듯이 리액트에서도 DOM요소에 이름을 붙이는 방법을 ref라고 함
➡️ DOM을 직접 건드려야 할 때 사용( ex. input에 포커스 주기, 스크롤 박스 조작하기 Canvas요소에 그림 그리기 등 )
아까 사용했던 코드를 useRef를 사용하여 등록 버튼을 눌렀을 때 포커스가 인풋 쪽으로 넘어가도록 코드를 작성해보면 다음과 같다.
import React, {useState , useMemo, useCallback} from 'react';
const getAverage = numbers => {
console.log('평균값 계산 중...')
if (numbers.length === 0) return 0;
const sum = numbers.reduce((a,b) => a+b);
return sum/ numbers.length;
}
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState('');
const inputEl = useRef(null); // ref 객체를 만들어줌
const onChange = useCallback(e => {
setNumber(e.target.value);
}, []);
const onInsert = useCallback(() => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber('');
inputEl.current.focus();
// ref 객체의 current 값은 우리가 선택하고자 하는 DOM을 가리킴
// 그리고 포커싱을 해주는 DOM API focus()를 호출함
}, [number, list]);
const avg = useMemo(() => getAverage(list), [list]);
return (
<div>
<input value = {number} onChange = {onChange} ref = {inputEl}/>
// 선택하고 싶은 DOM에 속성으로 ref 값을 설정
<button onClick = {onInsert}> 등록 </button>
<ul>
{list.map((value, index) => (
<li key = {index}> {value} </li>
))}
</ul>
<div>
<b>평균값: </b> {avg}
</div>
</div>
)
}
export default Average;
[React] API 호출하기 (0) | 2022.06.13 |
---|---|
[React] 투두리스트 컴포넌트 구조 및 코드 분석 (0) | 2022.06.09 |
[React] Hooks: useState, useEffect, useReducer (0) | 2022.05.31 |
[React] map과 filter를 통한 배열 관리 (0) | 2022.04.28 |
[React] 컴포넌트비교, 모듈 내보내기 및 가져오기, props, state (0) | 2022.04.15 |