8.4 use Memo
useMemo를 사용하면 함수형 컴포넌트 내부에서 발생하는 연산을 최적화 할 수 있다.
숫자를 등록할 때뿐만 아니라 인풋 내용이 수정될 때도 우리가 만든 getAverage 함수가 호출되는 것을 확인 할 수 있다. useMemo를 사용하면 렌더링하는 과정에서 특정 값이 바뀌었을 때만 연산을 실행하고, 원하는 값이 바뀌지 않았다면 이전에 연산했던 결과를 다시 사용하는 방식이다.
import React, {useState, useMemo} 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 onChange = e => {
setNumber(e.target.value);
}
const onClick = () => {
let newList = list.concat(parseInt(number));
setList(newList);
setNumber('');
}
const onKeyPress = (e) => {
if(e.key === 'Enter')
onClick();
}
const avg = useMemo(()=>getAverage(list), [list]);
return(
<>
<input value={number} onChange={onChange} onKeyPress={onKeyPress}/>
<button onClick={onClick}>등록</button>
<ul>
{list.map((value, index)=>(
<li key={index}>{value}</li>
))}
</ul>
<p>평균값: {avg}</p>
</>
)
};
export default Average;
Array.prototype.reduce()
developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
Array.prototype.reduce() - JavaScript | MDN
Array.prototype.reduce() reduce() 메서드는 배열의 각 요소에 대해 주어진 리듀서(reducer) 함수를 실행하고, 하나의 결과값을 반환합니다. The source for this interactive example is stored in a GitHub repository. If you'd
developer.mozilla.org
8.5 useCallback
useCallback은 useMemo와 상당히 비슷한 함수이다. 주로 렌더링 성능을 최적화해야 하는 상황에서 사용된다. 이 Hook을 사용하면 이번트 핸들러 함수를 필요할 때만 생성할 수 있다. 보통 컴포넌트가 리렌더링 될 때 컴포넌트에 포함된 함수 역시 새로 생된된다. 컴포넌트의 렌더링이 자주 발생하거나 렌더링해야 할 컴포넌트의 개수가 많다면 이 부분을 최적화해 주는 것이 좋다.
const onChange = useCallback(e=> {
setNumber(e.target.value);
}, []) //컴포넌트가 처음 렌더링될 때만 함수 생성
const onClick = useCallback(() => {
let newList = list.concat(parseInt(number));
setList(newList);
setNumber('');
}, [number, list]); //number 혹은 ㅣist가 바뀌었을 때만 함수 생성
const onKeyPress = (e) => { //ㅇ
if(e.key === 'Enter')
onClick();
}//얘는 useCallback 쓰면 warnig 뜸, onClick이랑 연관있어 보임
useCallback의 첫 번째 파라미터에는 생성하고 싶은 함수를 넣고, 두 번째 파라미터에는 배열을 넣으면 된다. 이 배열에는 어떤 값이 바뀌었을 때 함수를 새로 생성할 것인지 명시해야 한다.
onChange처럼 비어 있는 배열을 넣게 되면 컴포넌트가 렌더링될 때 단 한 번만 함수가 생성되며, onClick처럼 배열 안에 number와 list를 넣게 되면 인풋 내용이 바뀌거나 새로운 항목이 추가될 때마다 함수가 생성된다.
함수 내부에서 상태 값에 의존해야 할 때는 그 값을 반드시 두 번째 파라미터 안에 포함시켜 주어야 한다. 예를 들어 onClick의 newList는 기존의 number와 list를 조회하여 생성하기 때문에 배열 안에 number와 list를 꼭 넣어 주어야 한다.
결국 useCallback은 useMemo로 함수를 반환하는 상황에서 더 편하게 사용할 수 있는 Hook이다.
8.6 커스텀 Hooks 만들기
여러 컴포넌트에서 비슷한 기능을 공유할 경우, 자신만의 Hook으로 작성하여 로직을 재사용할 수 있다.
기존 Info 컴포넌트에서 여러 개의 인풋을 관리하기 위해 useReducer로 작성했던 로직을 useInputs라는 Hook으로 따로 분리해 보겠다.
import {useReducer} from 'react';
function reducer(state, action) {
return(
...state,
[action.name]: action.value;
);
}
export default function useInputs(initialForm) {
const [state, dispatch] = useReducer(reducer, initialForm);
const onChange = e => {
dispatch(e.target);
};
return [state, onChange];
}
const [state, onChange] = useInputs({
name: '',
nickname: ''
});
8.7 정리
리액트에서 Hooks 패턴을 사용하면 클래스형 컴포넌트를 사용하지 않고도 대부분의 기능을 구현할 수 있다.
메뉴얼에서는 새로 작성하는 컴포넌트의 경우 함수형 컴포넌트와 Hooks를 사용할 것을 권장하고 있다.
'Frontend > React' 카테고리의 다른 글
2021-04-23 :: 리액트 라우터로 SPA 개발하기 (0) | 2021.04.27 |
---|---|
2020-04-08 :: ref: DOM에 이름 달기 (0) | 2021.04.08 |
2021-04-05 :: Hooks1 (0) | 2021.04.05 |
2020-12-07 :: Event Handling (0) | 2020.12.08 |
2020-12-03 :: State (0) | 2020.12.04 |