기존 함수형 컴포넌트는 상태관리를 할 수 없었다.
그러나 react 16.8
부터 hooks
는 상태 관리가 가능한 useState
, 렌더링 직후 작업 설정하는 useEffect 등 여러 기능들이
제공하고 있다.
상태관리가 가능한 useState
const [상태값, 상태를 설정하는 함수] = useState(기본값)
useState에 기본값을 설정하면 [상태값, 상태를 설정하는 함수]를 리턴한다.
1 | //16.8 버전부터 useState 사용가능 |
렌더링 될때마다 특정 작업을 수행하도록 설정할 수 있는 useEffect
생명주기에 따라 특정 작업을 수행할 수 있다.1
2
3
4
5
6//// *** componentDidMount
useEffect(() => {}, [])
///// *** componentDidUpdate
useEffect(() => {}, [배열안에 검사하고 싶은 값 (현재 상태관리되고 있는 값 / props로 전달받은 값)])
///// *** componentUnMount, componentWillUpdate
useEffect(() => {}, return () => {});
1 | import React, { useState, useEffect } from 'react'; |
컴포넌트 업데이트 로직을 외부로 분리가능한 useReducer
바로 위에 Info예제를 보면 onchange이벤트를 각각 잡아서 함수를 생성하고 있다.
useReducer를 사용하면 기존에 redux에서 사용하던 action에 따라 상태값을 바꿀 수 있다.
const [state(현재 가르키고 있는 상태), dispatch(액션을 발생시키는 함수)] = useReducer(리듀서 함수, 기본값)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import React, { useReducer } from "react";
function reducer(state, action) {
switch(action.type) {
case 'INCREMENT':
return { value: state.value + 1 }
case 'DECREMENT':
return { value: state.value - 1 }
default:
return state;
}
}
const Counter_reducer = () => {
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;
렌더링 성능 최적화 useMemo
렌더링하는 과정에서 특정값이 바뀌었을 때만 연산을 실행한다.
숫자, 문자열, 객체처럼 일반 값을 재사용할 때 useMemo
를 사용한다.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46import React, { useState, useMemo, useCallback, useRef } 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 onInsert = e => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber('');
}; // number혹은 list가 바뀌었을 때만 함수 생성
//렌더링 성능 최적확: useMeomo
//렌더링하는 과정에서 특정값이 바뀌었을 때만 연산 실행, (list배열의 내용이 바뀔때마다 getAverage함수 호출)
const avg = useMemo(() => getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange} ref={inputEl} />
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
<div>
<b>평균 값:</b> {avg}
</div>
</div>
);
};
export default Average;
위와 같이 useMemo를 사용하지 않으면 렌더링 될때마다 getAverage라는 평균값을 계산하는 함수가 실행된다.
useMemo에 두번쩨 파라미터 []
에 list
가 들어간것은 list값이 바꼈을 때에만 실행하라는 의미이다.
즉 onInsert함수를 통해서 숫자가 추가될 때 getAverage가 실행된다.
렌더링 성능 최적화 useCallback
기존에는 리렌더링 할 때마다 함수를 새로 생성하지만 useCallback
는 이벤트 핸들러 함수를 필요할 때 생성한다.
useCallback(생성하고 싶은 함수, 배열: 어떤 값이 바뀌었을 때 함수를 새로 생성해주어야 하는지 명시)1
2
3
4/// **** 컴포넌트 처음 렌더링 될 때
useCallback(() => {}, [])
/// **** number나 list값이 바뀌었을 때
useCallback(() => {}, [number, list])
1 | import React, { useState, useMemo, useCallback, useRef } from 'react'; |
위에 예제에 추가로 useRef
를 사용했다.useRef
는 함수형 컴포넌트에서 ref를 쉽게 사용할 수 있게 해준다.