π React μ λ¬Έ 08 - Hook
π React μ
λ¬Έ 08 - 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μ λ£μΌλ©΄ μλλ€λ μ μ μ μν΄μΌ νλ€. - μμ‘΄μ± λ°°μ΄μ λ£μ§ μμ κ²½μ° λ λλ§μ΄ μΌμ΄λ λλ§λ€ ν¨μκ° μ€νλλ©°, μμ‘΄μ± λ°°μ΄μ λΉ λ°°μ΄μ λ£μ κ²½μ°
ComponentMountμμλ§ ν¨μκ° μ€νλλ€.
β
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μ μ΅μμ λ 벨μμλ§ νΈμΆν΄μΌ νλ€.
- λ°λ³΅λ¬Έμ΄λ 쑰건문 λλ μ€μ²©λ ν¨μ μμ΄ μλ
ReactFunctional Componentμ μ΅μμ λ 벨μμHookμ νΈμΆν΄μΌ νλ€. - μ΄ κ·μΉμ λ°λΌ
HookμComponentκ° λ λλ§ λ λλ§λ€ λ§€λ² κ°μ μμλ‘ νΈμΆλμ΄μΌ νλ€.
β
React Functional Componentμμ Hookμ νΈμΆν΄μΌ νλ€.
- μΌλ°
Javascriptν¨μμμHookμ νΈμΆνλ©΄ μ λλ€. ReactFunctional 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()ν¨μκ° νΈμΆλκ³ ,useUserStatusHookμ μ΄μ μ μ νλ μ¬μ©μλ₯Ό ꡬλ μ·¨μνκ³ μλ‘ μ νλ μ¬μ©μμ μ¨λΌμΈ μ¬λΆλ₯Ό ꡬλ νλ€.
μ€μ΅
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()λ₯Ό μ μΈνμ¬TeamComponentκ° λ λλ§ λ λλ§λ€useEffect()λ©μλμ νΈμΆ μ¬λΆμ νμ λ©€λ² μ μ λλ¬ μ¬λΆλ₯Ό μ½μ λ‘κ·Έμ μ°λλ€.countμνκ° λ³ν λλ§λ€ μ΅κ·Ό κ°μλ₯Ό μ½μ λ‘κ·Έμ μ°λλ€.- κ°μ
λ²νΌμ ν΄λ¦νλ©΄ λ©€λ²μ
countμκ° μ¦κ°νλ©°, μ μμ΄ κ½ μ°Όμ κ²½μ° λΉνμ±νλλ€. - νν΄ λ²νΌμ ν΄λ¦νλ©΄ λ©€λ²μ
countμκ° κ°μνλ€. - λν μ μμ΄ κ½ μ°° κ²½μ° λΉ¨κ° κΈμ¨λ‘ βμ μμ΄ κ°λ μ°Όμ΅λλ€.β λ¬Έκ΅¬κ° λ ΈμΆλλ€.
νκ³
Hookμ κ΅μ₯ν μ€μνκ³ λ 볡μ‘ν κΈ°λ₯μ΄μ΄μ μ¬μ€ μλ²½ν μμ§νμ§λ λͺ»νλ€.- λ°λ³΅ν΄κ°λ©° λΆμ‘±ν λΆλΆμ κ³΅λΆ ν΄μΌκ² λ€λ μκ°μ΄ λ€μλ€.
This post is licensed under CC BY 4.0 by the author.


