# 리액트를다루는기술
# Hooks
함수형 컴포넌트에서도 상태관리를 할 수 있게하는 Hooks.
리액트 메뉴얼에서 함수형 컴포넌트와 Hooks를 사용할 것을 권장함.
# 1. useState
const [value, setValue] = useState(0);
1
useState함수의 파라미터에는 상태의 기본값을 넣어준다.
value 기본값을 0으로 설정하겠다는 의미
useState()는 첫번째 원소는 상태값, 두번째 원소는 상태를 설정하는 함수인 배열 반환
const [name, setName] = useState("");
const [nickname, setNickname] = useState("");
1
2
2
다음과 같이 여러개 사용 가능
# 2. useEffect
리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hooks
/**
* 리액트컴포넌트가 렌더링 될때마다 작업 수행
*/
useEffect(() => {
console.log("렌더링이 완료되었습니다");
console.log({ name, nickname });
});
/**
* useEffect 화면에 맨 처음 렌더링 될 때만 실행하고 싶을때
* 함수의 두번째 파라미터로 비어있는 배열 넣어주기
*/
useEffect(() => {
console.log("useEffect 화면에 맨 처음 렌더링 될 때만 실행");
}, []);
/**
* useEffect 특정값 업데이트 될 때만 실행
*/
useEffect(() => {
console.log("useEffect name 업데이트 될 때만 실행");
}, [name]);
/**
* useEffect 뒷정리 함수 반환
*/
useEffect(() => {
console.log("effect");
console.log(name);
return () => {
console.log("cleanup");
console.log(name);
};
});
/**
* useEffect 언마운트 될때만 뒷정리 함수 반환
*/
useEffect(() => {
console.log("effect");
console.log(name);
return () => {
console.log("cleanup");
console.log(name);
};
}, [name]);
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
46
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
46
# 3. useReducer
useReducer(리듀서 함수, 리듀서의 기본값)
= [state(현재 가리키고 있는 상태), dispatch(액션을 발생시키는 함수)]
컴포넌트 업데이트 로직을 컴포넌트 바깥으로 빼낼 수 있다
function reducer(state, action) {
// action.type에 따라 다른 작업 수행
switch (action.type) {
case "INCREMENT":
return { value: state.value + 1 };
case "DECREMENT":
return { value: state.value - 1 };
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>
);
};
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function reducer(state, action) {
// 3. action 에 e.target 들어옴
return {
// state 초기값에 새로 들어온 요소 덮어씀.
...state,
[action.name]: action.value,
};
}
const Info = () => {
// 1. useReducer 사용. 파라미터로 리듀서 함수와 state 초기값을 넣어주면 state와 dispatch 함수 반환
const [state, dispatch] = useReducer(reducer, {
name: "",
nickname: "",
});
const { name, nickname } = state;
const onChange = (e) => {
console.log(e.target.name, e.target.value);
dispatch(e.target); // 2. dispatch 함수에 element 넣어줌.dispatch 함수는 reducer 함수를 호출해줌.
};
return (
<div>
<div>
<input name="name" value={name} onChange={onChange} />
<input name="nickname" value={nickname} onChange={onChange} />
</div>
<div>
<div>
<b>이름:</b> {name}
</div>
<div>
<b>닉네임: </b>
{nickname}
</div>
</div>
</div>
);
};
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
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
# 4. useMemo
const avg = useMemo(() => getAverage(list), [list]);
1
list 배열의 내용이 바뀔 때만 getAverage 함수가 호출
# 5. useCallback
렌더링 될때마다 함수를 새로 생성하는것을 방지. 어떤 값이 바뀌었을때만 함수 생성하기 원할때 사용.
비어있는 배열을 넣으면 렌더링 될 때 한번만 생성됨.
- useMemo : 숫자, 문자열, 객체 처럼 일반 값을 재사용
- useCallback : 함수 재사용
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 onChange = useCallback((e) => {
setNumber(e.target.value);
}, []); // 컴포넌트가 처음 렌더링될 때만 함수 생성
const onInsert = useCallback(() => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber("");
}, [number, list]); // number 혹은 list가 바뀌었을 때만 함수 생성
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;
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
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
# 6. useRef
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);
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가 바뀌었을 때만 함수 생성
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>
);
};
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
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
# 7. 커스텀 Hooks 만들기
컴포넌트에서 비슷한 기능을 공유할 경우, 이를 Hook으로 작성하여 로직을 재사용할 수 있다.
useReducer 포함 로직 포함 하여 useInputs로 감싸서 커스텀 Hooks 작성.
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];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const Info = () => {
const [state, onChange] = useInputs({
name: "",
nickname: "",
});
const { name, nickname } = state;
return (
<div>
<div>
<input name="name" value={name} onChange={onChange} />
<input name="nickname" value={nickname} onChange={onChange} />
</div>
<div>
<div>
<b>이름:</b> {name}
</div>
<div>
<b>닉네임: </b>
{nickname}
</div>
</div>
</div>
);
};
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
← 라이프사이클 메서드 Sass →