본 포스팅은 '실무에서 알아야할 기술은 따로 있다! 리액트를 다루는 기술'을 보고 정리한 글입니다.
Hook는 리액트 v16.8부터 함수형 컴포넌트에서도 상태 관리를 할 수 있는 기능을 제공합니다.
useState
는 컴포넌트에서 상태를 관리할 때 기본적으로 사용하는 Hook입니다.
react
로부터 import 해줍니다.useState(초기값)
을 통해 초기값을 지정해줍니다.set변수명
을 통해 변화시킵니다.import React, { useState } from 'react';
const Info = () => {
const [name, setName] = useState('');
const [nickName, setNickName] = useState('');
const onChangeName = e => {
setName(e.target.value);
};
const onChangeNickName = e => {
setNickName(e.target.value);
};
...
}
useEffect
는 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook입니다.
componentDidMount
와 componentDidUpdate
를 합친 형태라고 볼 수 있습니다.
import React, { useState, useEffect } from 'react';
const Info = () => {
const [name, setName] = useState('');
const [nickName, setNickName] = useState('');
useEffect(() => {
console.log('rendering ready');
console.log({ name, nickName });
});
...
};
export default Info;
위 처럼 작성할 경우, 렌더링이 될 때마다 useEffect
가 불리게 됩니다.
업데이트를 제외하고 처음 렌더링 할 때만 useEffect
를 사용하려면 아래와 같이 두 번째 파라미터에 빈 값을 넣어줍니다.
useEffect(() => {
console.log('only when mounted');
}, []);
특정값이 업데이트 될 때만 실행하고 싶다면 아래와 같이 모니터링하고 싶은 특정값을 두 번째 파라미터로 넣어줍니다.
useEffect(() => {
console.log(name);
}, [name]);
컴포넌트가 언마운트되기 전이나 업데이트 되기 전에 어떠한 작업을 수행하고 싶다면 useEffect
에 return으로 수행하고 싶은 cleanup함수를 넘겨줍니다.
useEffect(() => {
console.log('effect');
console.log(name);
return (() => {
console.log('cleanup');
console.log(name);
});
}, [name]);
useReducer
함수는 더 다양한 상황에 따라 다양한 상태의 다른 값을 업데이트 해줄 때에 사용하는 Hook입니다.
action
을 통해 업데이트에 필요한 값을 전달 받아 새로운 상태를 반환합니다.
import React, { useState, useEffect, useReducer } from 'react';
function reducer(state, action) {
return {
...state,
[action.name]: action.value
};
}
const Info = () => {
const [state, dispatch] = useReducer(reducer, {
name: '',
nickName: ''
});
const { name, nickName } = state;
const onChange = e => {
dispatch(e.target);
}
...
}
위의 코드는 값이 추가될 때마다 평균값을 연산하는 코드입니다.
하지만, 로그를 확인해보면 버튼을 눌렀을 때만 값을 출력하는 것이 아니라 숫자가 변경될 때마다 getAverage
함수가 호출되는 것을 확인할 수 있습니다.
이렇게 버튼이 눌렸을 때만 연산을 수행해도 되는데 숫자가 변경될 때마다 연산을 수행하는 것을 방지하기 위해 useMemo
를 사용합니다. 즉, 렌더링 성능을 최적화 시키는 데에 사용한다고 할 수 있습니다.
import React, { useState, useMemo } from 'react';
...
const Average = () => {
...
const avg = useMemo(() => getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange} />
<button onClick={onInsert}>Insert</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
<div>
<b>Average:</b>{avg}
</div>
</div>
);
}
이제, 숫자가 변화하는 것이 아니라 list 배열의 내용이 바뀔 때만 getAverage
함수가 호출됩니다.
useCallback
도 렌더링 성능을 최적화시키는 데에 사용하는 함수입니다. useMemo
와 다르게 useCallback
은 함수 재사용을 가능하게 하여 성능을 향상시킵니다.
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('');
};
...
}
위의 코드는 컴포넌트가 리렌더링 될 때마다 onChange
함수와 onInsert
함수를 새로 생성합니다. 이러한 경우, 컴포넌트의 렌더링이 자주 발생하거나 컴포넌트의 개수가 많아질 때 최적화를 해주는 것이 좋습니다.
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState('');
const onChange = useCallback(e => {
setNumber(e.target.value);
}, []);
const onInsert = useCallback(e => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber('');
}, [number, list]);
...
}
위의 코드에서는 useCallback
을 통해 함수 생성을 최적화하였습니다. 첫 번째 파라미터에는 생성하고 싶은 함수를 넣고, 두 번째 파라미터에는 어떤 값이 바뀌었을 때 함수를 새로 생성해야 하는지 명시합니다.
두 번째 파라미터에 빈 배열을 넣을 경우, 컴포넌트 렌더링 되었을 때 단 한 번만 함수가 생성되고, 값을 넣었을 경우, 해당 값에 변화가 있거나 새로운 항목이 추가될 경우 함수가 새로 생성됩니다.
useRef
는 함수형 컴포넌트에서 ref
를 쉽게 사용할 수 있도록 해줍니다. 아래는 버튼을 눌렀을 때, 포커스를 안쪽으로 넘어가도록 한 코드입니다.
import React, { useState, useMemo, useCallback, useRef } from 'react';
...
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState('');
const inputE1 = useRef(null);
...
const onInsert = useCallback(e => {
...
inputE1.current.focus();
}, [number, list]);
const avg = useMemo(() => getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange} ref={inputE1} />
...
</div>
);
};
export default Average;
또한, useRef
는 렌더링과 관련되지 않은 값들을 관리할 때에 사용할 수 있습니다.
useState
: Component의 상태를 업데이트 할 때useEffect
: 컴포넌트가 렌더링 될 때 동작을 수행하도록 할 때useReducer
: 다양한 상태의 다양한 값을 업데이트 해줄 때useMemo
: 숫자, 문자열, 객체처럼 일반 값을 재사용할 때useCallback
: 함수를 재사용할 때useRef
: ref
를 사용할 때