π React μ λ¬Έ β § - Hook
π React μ
λ¬Έ β
§ - Hook
π
γμνμ μ²μ λ§λ 리μ‘νΈγ
λ₯Ό μ½κ³ μ 리ν κΈμ λλ€.
Hook
μ΄λ?
- κΈ°μ‘΄μ
Functional Component
λClass Component
μλ λ€λ₯΄κ² μ½λλ κ΅μ₯ν κ°κ²°νκ³ λ³λλ‘ΒState
λ₯Ό μ μνκ±°λComponent
μ μλͺ μ£ΌκΈ° ν¨μλ₯Ό μ¬μ©ν μ μμλ€. - μ΄λ° κΈ°λ₯μ μ§μνκΈ° μν΄ λμ¨ κ²μ΄ λ°λ‘
Hook
μ΄λ€. Hook
μ΄λΌλ λ¨μ΄λ κ°κ³ 리λ₯Ό λ»νλλ°, κ°κ³ 리λ₯Ό κ±°λ κ²μ²λΌ μλ μ‘΄μ¬νλ μ΄λ€ κΈ°λ₯μ λΌμ΄ λ€μ΄κ° κ°μ΄ μννλ κ²μ μλ―Ένλ€.Hook
μ μ΄λ¦μ λͺ¨λΒuse
λ‘ μμνλ€.- κ°λ°μκ° μ§μ
Custom Hook
μ λ§λ€μ΄ μ¬μ©ν κ²½μ° μ΄λ¦μ λ§μλλ‘ μ§μ μλ μμ§λ§use
λ₯Ό λͺ μν΄ μ£Όλ κ²μ΄ μ¬λ°λ₯΄λ€.
Hook
μ μ’
λ₯
β
useState
1
2
3
4
5
6
7
8
9
10
11
12
function Counter(props) {
var count = 0;
return (
<div>
<p>μ΄ {count}λ² ν΄λ¦νμ΅λλ€.</p>
<button onClick={() => count++}>
ν΄λ¦
</button>
</div>
);
}
- μ μ½λλ λ²νΌμ ν΄λ¦νλ©΄
count
κ°μ μ¦κ° μν¬ μλ μμ§λ§ λ λλ§μ΄ λ€μ μΌμ΄λμ§ μμ κ°±μ λcount
κ°μ΄ νλ©΄μ νμλμ§ μλλ€. - λ°λΌμ μλμ μ½λμ κ°μ΄
State
λ₯Ό μ¬μ©ν΄μ κ°μ΄ λ°λ λλ§λ€ λ€μ λ λλ§ λλλ‘ ν΄μΌ ν νμμ±μ΄ μλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React, { useState } from "react";
function Counter(props) {
const [count, setCount] = useState(0);
return (
<div>
<p>μ΄ {count}λ² ν΄λ¦νμ΅λλ€.</p>
<button onClick={() => setCount(count + 1)}>
ν΄λ¦
</button>
</div>
);
}
- μμ
Counter(props)
λ©μλλ λ²νΌμ΄ λλ Έμ λΒsetCount()
Β ν¨μλ₯Ό νΈμΆν΄μcount
λ₯Ό μ¦κ° μν¨λ€. count
μ κ°μ΄ λ³κ²½λλ©΄Component
κ° λ€μ λ λλ§λλ©΄μ νλ©΄μ μ¦κ° λcount
κ°μ νμν μ μλ€.Class Component
μμλsetState()
ν¨μ νλλ₯Ό μ¬μ©ν΄μ λͺ¨λState
κ°μ κ°±μ ν μ μμμ§λ§Functional Component
μμλ λ³μ κ°κ°μ λν΄set
ν¨μκ° λ°λ‘ μ‘΄μ¬νλ€.
β
useEffect
1
useEffect(μ΄ννΈ ν¨μ, μμ‘΄μ± λ°°μ΄);
Side Effect
λ₯Ό μ²λ¦¬νκΈ° μν ν μ΄λ€.Side Effect
λΌκ³ νλ©΄ λΆμ μ μΈ λλμ κ°μ§κ³ μμ§λ§React
μμ λ§νλSide Effect
λ μλ²μμ λ°μ΄ν°λ₯Ό λ°μμ€κ±°λ μλμΌλ‘ΒDOM
μ λ³κ²½νλ λ±μ μΌλ°μ μΈ μ΄ννΈλ₯Ό μλ―Ένλ€.Class Component
μμ μ 곡νλ μλͺ μ£ΌκΈ° ν¨μμΈcomponentDidMount()
,componentDidUpdate()
,componentWillUnmount()
μ λμΌν κΈ°λ₯μ νλλ‘ ν΅ν©ν΄μ μ 곡νλ€.- μμ‘΄μ± λ°°μ΄ μμ μλ λ³μ μ€μ νλλΌλ κ°μ΄ λ³κ²½λμμ λ μ΄ννΈ ν¨μκ° μ€νλλ€.
- κΈ°λ³Έμ μΌλ‘ μ΄ννΈ ν¨μλ μ²μ
Component
κ° λ λλ§ λ μ΄νμ μ λ°μ΄νΈλ‘ μΈν μ¬λ λλ§ μ΄νμ μ€νλλ€. - λ§μ½ μ΄ννΈ ν¨μκ°
Mount
,Unmount
μμ λ¨ ν λ²λ§ μ€νλκ² νκ³ μΆμΌλ©΄ μμ‘΄μ± λ°°μ΄μ λΉ λ°°μ΄μ λ£μΌλ©΄ λλ€. - μ΄λ κ² νλ©΄ μ΄ννΈκ°
props
λState
μ μλ μ΄λ€ κ°μλ μμ‘΄νμ§ μμΌλ―λ‘ μ¬λ¬ λ² μ€νλμ§ μλλ€. - μμ‘΄μ± λ°°μ΄ μμ΄Β
useEffect()
λ₯Ό μ¬μ©νλ©΄React
λΒDOM
μ΄ λ³κ²½λ μ΄νμ ν΄λΉ μ΄ννΈ ν¨μλ₯Ό μ€ννλΌλ μλ―Έλ‘ λ°μλ€μΈλ€. - κ·Έλμ
Component
κ° μ²μ λ λλ§ λ λλ₯Ό ν¬ν¨ν΄μ λ§€λ² λ λλ§ λ λλ§λ€ μ΄ννΈκ° μ€νλλλ°, κ²°κ³Όμ μΌλ‘componentDidMount()
,componentDidUpdate()
μ λμΌν μν μ νκ² λλ€. componentWillUnmount()
λuseEffect()
μμ λ°ννλ ν¨μλComponent
κ°Unmount
λ λ νΈμΆλλ€.
β
useMemo
1
2
3
const memoizedValue = useMemo(() => {
return ν¨μ(μμ‘΄μ± λ³μ1, μμ‘΄μ± λ³μ2);
}, [μμ‘΄μ± λ³μ1, μμ‘΄μ± λ³μ2]);
Memoized value
λ₯Ό λ°ννλHook
μ΄λ€.- μμ‘΄μ± λ°°μ΄μ λ€μ΄ μλ λ³μκ° λ³νμ κ²½μ°μλ§Β ν¨μλ₯Ό νΈμΆνμ¬ μλ‘μ΄ κ²°κ³Όλ₯Ό λ°ννλ©°, κ·Έλ μ§ μμ κ²½μ°λ κΈ°μ‘΄ ν¨μμ κ²°κ³Όλ₯Ό κ·Έλλ‘ λ°ννλ€.
Component
κ° λ€μ λ λλ§ λ λλ§λ€ μ°μ°μ΄ λ§μ μμ μ λ°λ³΅μ νΌν μ μλ€.- λ λλ§μ΄ μΌμ΄λλ λμ μ€νν΄μλ μ λ μμ
μΒ
useMemo
μ λ£μΌλ©΄ μλλ€λ μ μ μ μν΄μΌ νλ€. - μμ‘΄μ± λ°°μ΄μ λ£μ§ μμ κ²½μ° λ λλ§μ΄ μΌμ΄λ λλ§λ€ ν¨μκ° μ€νλλ©°, μμ‘΄μ± λ°°μ΄μ λΉ λ°°μ΄μ λ£μ κ²½μ°
Component
Mount
μμλ§ ν¨μκ° μ€νλλ€.
β
useCallback
useMemo
μ μ μ¬νμ§λ§ ν κ°μ§ μ°¨μ΄μ μ κ°μ΄ μλ ν¨μλ₯Ό λ°ννλ€.ΒuseCallback
μμ νλΌλ―Έν°λ‘ λ°λ μ΄ ν¨μλ₯ΌCallback
μ΄λΌκ³ λΆλ₯Έλ€.- μμ‘΄μ± λ°°μ΄μ λ°λΌ
Memoized value
λ₯Ό λ°ννλ€λ μ μμλuseMemo
μ μμ ν λμΌνλ€. - λ§μ½Β
useCallback
μ μ¬μ©νμ§ μκ³Component
λ΄μ ν¨μλ₯Ό μ μνλ€λ©΄ λ§€λ² λ λλ§μ΄ μΌμ΄λ λλ§λ€ ν¨μκ° μλ‘ μ μλλ€. - λ°λΌμ ν΄λΉ
Hook
μ μ¬μ©νμ¬ νΉμ λ³μμ κ°μ΄ λ³ν κ²½μ°μλ§ ν¨μλ₯Ό λ€μ μ μνμ¬ λ°λ³΅μ μμ μ£Όλ κ²μ΄ μ¬λ°λ₯΄λ€.
β
useRef
1
const refContainer = useRef(μ΄κΉκ°);
Reference
λ₯Ό μ¬μ©νκΈ° μνHook
μΌλ‘,Reference
κ°μ²΄λ₯Ό λ°ννλ€.React
μμReference
λ νΉμ Component
μ μ κ·Όν μ μλ κ°μ²΄λ₯Ό μλ―Ένλ€.Reference
κ°μ²΄μλcurrent
λΌλ μμ±μ΄ μλλ° μ΄λ νμ¬ μ°Έμ‘°νκ³ μλElement
λ₯Ό μλ―Ένλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function TextInputWithFocusButton(props) {
const inputElem = useRef(null);
const onButtonClick = () => {
inputElem.current.focus();
};
return (
<div>
<input ref={inputElem} type="text"/>
<button onClick={onButtonClick}>Focus the input</button>
</div>
);
}
- μ μ½λλ λ²νΌμ ν΄λ¦νλ©΄Β
input
Β νκ·Έλ₯ΌFocusing
νλ μμ μ΄λ€. - λ§€λ² λ λλ§ λ λλ§λ€ νμ κ°μΒ
Reference
Β κ°μ²΄λ₯Ό λ°ννλ€. - μ£Όμν΄μΌ ν μ μΒ
useRef
Β ν μ λ΄λΆμΒcurrent
Β μμ±μ΄ λ³κ²½λλλΌλ λ€μ λ λλ§ νμ§ μλλ€λ κ²μ΄λ€. - λ°λΌμΒ
Reference
μΒDOM node
κ° μ°κ²°λκ±°λ λΆλ¦¬λ κ²½μ° μ΄λ€ μ½λλ₯Ό μ€ννκ³ μΆλ€λ©΄Βcallbackref
Β λ°©μμ μ¬μ©ν΄μΌ νλ€. - μ΄λΒ
DOM node
μΒref
Β μμ±μΒReference
κ°μ²΄ λμ ΒuseCallback
Β λ°ν ν¨μλ₯Ό λ£μ΄μ£Όλ κ²μ΄λ€. - μ΄λ κ² λλ©΄ μμ
Component
κ° λ³κ²½λμμ λ μλ¦Όμ λ°μ μ μκ³ , μ΄λ₯Ό ν΅ν΄ λ€λ₯Έ μ 보λ€μUpdate
ν μ μλ€.Β
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function MeasureExample(props) {
const [height, setHeight] = useState(0);
const measuredRef = useCallback(node => {
if (node !== null) {
setHeight(node.getBoundingClientRect().height);
}
}, []);
return (
<div>
<h1 ref={measureRef}>μλ
, 리μ‘νΈ</h1>
<h2>μ ν€λμ λμ΄λ {Math.round(height)}pxμ
λλ€.</h2>
</div>
);
}
- μμ μμ μμλΒ
h1
Β νκ·Έμ λμ΄λ₯ΌUpdate
νκ³ μλ€.Β useCallback
μ μμ‘΄μ± λ°°μ΄λ‘ λΉ λ°°μ΄μ΄ λ€μ΄κ° μμΌλ―λ‘Mount
,Unmount
μμλ§Callback
ν¨μκ° νΈμΆλλ€.Β
Hook
μ κ·μΉ
β
Hook
μ μ΅μμ λ 벨μμλ§ νΈμΆν΄μΌ νλ€.
- λ°λ³΅λ¬Έμ΄λ 쑰건문 λλ μ€μ²©λ ν¨μ μμ΄ μλ
React
Functional Component
μ μ΅μμ λ 벨μμHook
μ νΈμΆν΄μΌ νλ€. - μ΄ κ·μΉμ λ°λΌ
Hook
μComponent
κ° λ λλ§ λ λλ§λ€ λ§€λ² κ°μ μμλ‘ νΈμΆλμ΄μΌ νλ€.
β
React
Functional Component
μμ Hook
μ νΈμΆν΄μΌ νλ€.
- μΌλ°
Javascript
ν¨μμμHook
μ νΈμΆνλ©΄ μ λλ€. React
Functional Component
μμ νΈμΆνκ±°λ μ§μ λ§λCustom Hook
μμ νΈμΆν μ μλ€.
Custom Hook
- μ¬λ¬
Component
μμ λ°λ³΅μ μΌλ‘ μ¬μ©λλ λ‘μ§μHook
μΌλ‘ λ§λ€μ΄ μ¬μ¬μ©νκΈ° μν΄Custom Hook
μ λ§λ λ€. - νλΌλ―Έν°λ‘ 무μμ λ°μμ§, μ΄λ€ κ²μ λ°νν μ§ κ°λ°μκ° μ§μ μ ν μ μλ€.Β
Component
λͺ μ κΌuse
λ‘ μμνλλ‘ νμ¬ ν΄λΉComponent
μμHook
μ νΈμΆνλ€λ κ²μ λͺ μν΄μΌ νλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function UserStatus(props) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ServerAPI.subscribeUserStatus(props.user.id, handleStatusChange);
return () => {
ServerAPI.unsubscribeUserStatus(props.user.id, handleStatusChange);
};
});
if (isOnline === null) {
return 'λκΈ°μ€...';
}
return isOnline ? 'μ¨λΌμΈ' : 'μ€νλΌμΈ';
}
- μκΈ° μ½λμ
Custom Hook
μ μ μ©νκ³ μ νλ€.Β isOnline
μ΄λΌλState
μ λ°λΌ μ¬μ©μμ μ¨λΌμΈ μ¬λΆλ₯Ό ν μ€νΈλ‘ 보μ¬μ£ΌλComponent
μ΄λ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function useUserStatus(userId) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ServerAPI.subscribeUserStatus(props.user.id, handleStatusChange);
return () => {
ServerAPI.unsubscribeUserStatus(props.user.id, handleStatusChange);
};
});
return isOnline;
}
State
μ κ΄λ ¨λ μ€λ³΅ λ‘μ§μΒuseUserStatus
λΌλCostom Hook
μΌλ‘ μΆμΆν΄λΈ κ²μ΄λ€.- μ΄μ
UserStatus
μUserListItem
μμCustom Hook
μ μ μ©νλ©΄ λλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// UserStatus.jsx
function UserStatus(props) {
const isOnline = useUserStatus(props.user.id);
if (isOnline === null) {
return 'λκΈ°μ€...';
}
return isOnline ? 'μ¨λΌμΈ' : 'μ€νλΌμΈ';
}
// UserListItem.jsx
function UserListItem(props) {
const isOnline = useUserStatus(props.user.id);
return (
<li style=>
{props.user.name}
</li>
);
}
- μμ²λΌ κ°μ
Custom Hook
μ μ¬μ©νλ λ κ°μComponent
κ°State
λ₯Ό 곡μ νλ κ²μ μλλ€. - λ¨μνΒ
State
Β μ°κ΄ λ‘μ§μ μ¬μ¬μ©μ΄ κ°λ₯νκ² λ§λ κ² λΏμ΄λ€. - μ¬λ¬ κ°μ
Component
μμ νλμCustom Hook
μ μ¬μ©νλλΌλComponent
λ΄λΆμState
λeffects
λ μ λΆ λΆλ¦¬λμ΄ μλ€.
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
const userList = [
{ id : 1, name : 'Inje' },
{ id : 2, name : 'Mike' },
{ id : 3, name : 'Steve' }
];
function ChatUserSelector(props) {
const [userId, setUserId] = userState(1);
const isUserOnline = useUserStatus(userId);
return (
<div>
<Circle color={isUserOnline ? 'green' : 'red'}/>
<select
value={userId}
onChange={event => setUserId(Number(event.target.value))}>
{userList.map(user => (
<option key={user.id} value={user.id}>
{user.name}
</option>
))}
</select>
</div>
);
}
Hook
κ°μ λ°μ΄ν°λ₯Ό 곡μ νλ μμ μ½λμ΄λ€.userId
κ° λ³κ²½λ λλ§λ€setUserId()
ν¨μκ° νΈμΆλκ³ ,useUserStatus
Hook
μ μ΄μ μ μ νλ μ¬μ©μλ₯Ό ꡬλ μ·¨μνκ³ μλ‘ μ νλ μ¬μ©μμ μ¨λΌμΈ μ¬λΆλ₯Ό ꡬλ νλ€.
μ€μ΅
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
47
48
49
50
51
52
53
54
import React, { useEffect, useState } from "react";
const MAX_CAPACITY = 10;
const buttonStyle = {
padding: "8px 16px",
marginRight: "8px",
backgroundColor: "#4CAF50",
color: "white",
border: "none",
borderRadius: "4px",
cursor: "pointer",
fontSize: "14px",
};
const disabledButtonStyle = {
...buttonStyle,
backgroundColor: "#ccc",
cursor: "not-allowed",
};
function UseCounter(initialValue) {
const [count, setCount] = useState(initialValue);
const increaseCount = () => setCount((count) => count + 1);
const decreaseCount = () => setCount((count) => Math.max(count - 1, 0));
return [count, increaseCount, decreaseCount];
}
function ManageTeamMembers(props) {
const [isFull, setIsFull] = useState(false);
const [count , increaseCount, decreaseCount] = UseCounter(0)
useEffect(() => {
console.log("useEffect() λ©μλκ° νΈμΆλμμ΅λλ€.");
console.log(`μ μ λλ¬μ¬λΆ ${isFull}`);
});
useEffect(() => {
setIsFull(count >= MAX_CAPACITY);
console.log(`μ΅κ·Ό κ°μ: ${count}`);
}, [count]);
return (
<div style=>
<p>{`νμ κ°μ
ν λ©€λ²λ μ΄ ${count}λͺ
μ
λλ€.`}</p>
<button onClick={increaseCount} style={isFull ? disabledButtonStyle : buttonStyle} disabled={isFull}>κ°μ
</button>
<button onClick={decreaseCount} style={buttonStyle}>νν΄</button>
{isFull && <p style=>μ μμ΄ κ°λμ°Όμ΅λλ€.</p>}
</div>
);
}
export default ManageTeamMembers;
useEffect()
λ₯Ό μ μΈνμ¬Team
Component
κ° λ λλ§ λ λλ§λ€useEffect()
λ©μλμ νΈμΆ μ¬λΆμ νμ λ©€λ² μ μ λλ¬ μ¬λΆλ₯Ό μ½μ λ‘κ·Έμ μ°λλ€.count
μνκ° λ³ν λλ§λ€ μ΅κ·Ό κ°μλ₯Ό μ½μ λ‘κ·Έμ μ°λλ€.- κ°μ
λ²νΌμ ν΄λ¦νλ©΄ λ©€λ²μ
count
μκ° μ¦κ°νλ©°, μ μμ΄ κ½ μ°Όμ κ²½μ° λΉνμ±νλλ€. - νν΄ λ²νΌμ ν΄λ¦νλ©΄ λ©€λ²μ
count
μκ° κ°μνλ€. - λν μ μμ΄ κ½ μ°° κ²½μ° λΉ¨κ° κΈμ¨λ‘ βμ μμ΄ κ°λ μ°Όμ΅λλ€.β λ¬Έκ΅¬κ° λ ΈμΆλλ€.
νκ³
Hook
μ κ΅μ₯ν μ€μνκ³ λ 볡μ‘ν κΈ°λ₯μ΄μ΄μ μ¬μ€ μλ²½ν μμ§νμ§λ λͺ»νλ€.- λ°λ³΅ν΄κ°λ©° λΆμ‘±ν λΆλΆμ κ³΅λΆ ν΄μΌκ² λ€λ μκ°μ΄ λ€μλ€.
This post is licensed under CC BY 4.0 by the author.