React Hooks
# 시작하며
오늘은 앞서 class component와 function component에 대한 챕터에서 잠시 언급했던 React Hooks에 대해 알아볼 것이다. Hooks는 class component에서는 가능하지만 function component에서는 사용하지 못하는 단점을 보완하기 위해 React v16.8부터 도입된 기능이다. 함수형 component에서도 상태관리가 가능하도록 useState() 개념을 도입하고, rendering 직후 함수 초기에 실행되는 작업을 설정하는 useEffect() 등의 기술을 제공하여 기존의 함수형 component에서 할 수 없었던 다양한 작업을 가능하게 한다.
# 개요
- useState
- useEffect
- useReducer
- useMemo
- useCallback
- useRef
# useState
가장 먼저 알아볼 Hook는 useState이다. 상태 관리를 위해 사용하는 가장 기본적인 Hook이며, 컴포넌트 내부에서 가변적인 상태 관리를 할 수 있도록 설정할 수 있다.
import React, { useState } from ‘react‘;
const useState_example = () => {
const [value, setValue] = useState(0);
return(
<>
<p>현재 value값은 {value}이다.<p/>
<button onClick={()=> setValue(value+1)}>value+1</button>
</>
);
}
export default useState_example;
useState를 사용하기 위해서는 먼저 react에 내장되어 있는 useState를 import 함으로써 시작한다. 위 코드를 보면, state를 선언함에 있어 useState로 초기 값을 0으로 설정해주었다. 해당 함수가 호출되면 배열을 반환하게 되는데 첫 번째 요소 value는 상태 값이며 두 번째 setValue는 해당 상태 값을 설정하거나 변경하는 함수이다. 해당 setValue에 파라미터로 변경 값을 넣고 호출하면 전달받은 파라미터로 상태 값이 변경되고 컴포넌트가 re-rendering 된다.
# useEffect
다음은 useEffect에 대해 살펴보면, 해당 함수는 React component가 rendering 될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook이다. class 컴포넌트에서 componentDidMount와 componentDidUpdate를 합친 형태와 동일한 작용을 한다.
import React, { useState, useEffect } from ‘react‘;
const useEffectExample = () => {
const [name, setName] = useState(“);
const [nickname, setNickname] = useState(“);
useEffect(() => {
console.log(‘렌더링 완료’);
console.log(name, nickname);
});
const onChangeName = e => {
setName(e.target.value);
};
const onChangeNickname = e => {
setNickname(e.target.value);
};
return (
(…)
);
};
export default useEffectExample;
위 코드는 useEffect를 사용하는 간단한 예제이다. 하지만 위와 다르게, useEffect 내부 함수를 Mount 될 때만 실행하고 싶다면 어떻게 해야 할까? 즉 React에서 어떠한 페이지에 들어와서 function component를 실행할 때, 들어오는 첫 순간에만 실행시키고 싶은 코드가 있다면 useEffect를 활용할 수 있다.
useEffect(()=>{
console.log("Mount될 때만 실행");
},[])
위 코드는 useEffect 내부에 []를 삽입하는데, [] 내부에 빈 값이 있는 경우에는, Mount되는 경우에만 해당 함수를 실행하도록 설정된다. 그렇다면 내부에 다른 특정 값이 들어있다면 어떻게 될까?
useEffect(()=>{
console.log(value);
},[value])
다음과 같이 useEffect 두 번째 파라미터에 특정 값이 들어있다면, 해당 값이 업데이트 될 때마다 계속해서 useEffect가 호출된다. 그리하여 어떠한 값을 클릭하거나 변경했을 때 상태 관리가 유용하다. 하지만 원하지 않는 경우에도 계속해서 반복 호출하는 경우도 발생할 수 있어서 사용에 주의가 필요하다.
# useReducer
useReducer는 useState보다 다양한 컴포넌트 상황에서 다양한 상태 값을 업데이트 할 수 있는 Hook이다. reducer는 현재 상태, 그리고 업데이트를 위해 필요한 정보를 담은 action값을 전달받아 새로운 상태를 반환하는 함수이다. 이때 reducer함수에서 새로운 상태를 만들고자 할 때는, 반드시 불변성을 유지해 주어야 한다.
import React, { useReducer } from ‘react‘;
function reducer(state, action) { // action.type에 따라 다른 작업 수행
switch (action.type) {
case ‘INCREMENT‘:
return { value: state.value + 1 };
case ‘DECREMENT‘:
return { value: state.value - 1 };
default: // default 일 때, 기존 상태 반환
return state;
}
}
const Counter = () => {
const [state, dispatch] = useReducer(reducer, { value: 0 });
return (
<div>
<p>
현재 카운터 값은 <b>{state.value}</b>입니다.
</p>
<button onClick={() => dispatch({ type: ‘INCREMENT‘ })}>+1</button>
<button onClick={() => dispatch({ type: ‘DECREMENT‘ })}>-1</button>
</div>
);
};
export default Counter;
첫 번째 파라미터에는 reducer함수를 담고, 두 번째는 기본 값을 넣어준다. state는 현재 가리키는 상태를 의미하며, dispatch는 액션 발생 함수로 사용된다. useReducer의 장점은, 컴포넌트 업데이트 로직을 밖으로 빼내는 것이 가능하다는 것이다.
# useMemo
useMemo에 대해 알아보면, 함수형 컴포넌트 내부에서 발생하는 연산을 최적화 시켜주는 함수이다.
import React, { useState, useMemo } from ‘react‘;
const getAverage = numbers => {
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 onInsert = () => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber(“);
};
const avg = useMemo(() => getAverage(list), [list]);
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> {avg}
</div>
</div>
);
};
export default Average;
해당 코드는 간단하게 input 창에 입력한 수를 list에 저장하고, getAverage라는 함수를 통해 평균값을 계산하는 과정을 나타낸 것이다. 단순히 getAverage 함수를 호출하여 연산하는 것이 아닌, useMemo Hook을 사용하여 rendering 하는 과정에서 특정 값이 바뀌었을 대만 연산을 실행하기 때문에 최적화 작업을 수행할 수 있다.
# useCallback
useCallback은 useMemo와 기능이 비슷한 함수이다. 주로 rendering 성능을 최적화하는 목적을 사용된다. 해당 Hook을 사용하면 이벤트 헨들러 함수를 필요 시에만 생성할 수 있다.
const onChange = useCallback(e => {
setNumber(e.target.value);
}, []); // 컴포넌트가 처음 렌더링될 때만 함수 생성
const onInsert = useCallback(() => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber(“);
}, [number, list]); // number 혹은 list가 바뀌었을 때만 함수 생성
useMemo를 사용하는 코드에서 change와 click시 호출되는 함수를 변경한 것이다. 첫 번째 파라미터에는 생성 함수를 넣고, 두 번째는 배열을 삽입한다. 이로인해, 두 번째 파라미터 [] 내부 값이 변경될 때마다 함수를 새로 생성하여 실행한다. 결국 useCallback은 useMemo로 함수를 반환하는 상황에서 더욱 편하게 사용할 수 있는 Hook이다.
# useRef
해당 Hook은 함수형 컴포넌트에서 ref를 쉽게 사용할 수 있도록 해주는 함수이다.
const inputEl = useRef(null);
const onChange = useCallback(e => {
setNumber(e.target.value);
}, []); // 컴포넌트가 처음 렌더링될 때만 함수 생성
const onInsert = useCallback(() => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber(“);
inputEl.current.focus();
}, [number, list]); // number 혹은 list가 바뀌었을 때만 함수 생성
return (
<div>
<input value={number} onChange={onChange} ref={inputEl} />
(...)
</div>
);
};
export default Average;
'Web Frontend' 카테고리의 다른 글
React JSX (0) | 2022.07.26 |
---|---|
React (0) | 2022.07.15 |
React Lifecycle method (0) | 2022.07.12 |
React ForEach, Map (0) | 2022.07.12 |
React Component (0) | 2022.07.07 |