๐ Hook์ ๊ท์น
- Hook์ ๋ฌด์กฐ๊ฑด ์ต์์ ๋ ๋ฒจ์์๋ง ํธ์ถํด์ผ ํ๋ค. ( ๋ฆฌ์กํธ ํจ์ ์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ ) -> ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง๋ ๋๋ง๋ค ๋งค๋ฒ ๊ฐ์ ์์๋ก ํธ์ถ๋์ด์ผ ํ๋ค.
- ๋ฆฌ์กํธ ํจ์ ์ปดํฌ๋ํธ์์๋ง Hook์ ํธ์ถํด์ผ ํ๋ค.
๐ Custom Hook ๋ง๋ค๊ธฐ
๊ธฐ๋ณธ์ ์ผ๋ก ์ ๊ณต๋๋ Hooks ์ด์ธ์ ์ถ๊ฐ์ ์ผ๋ก ํ์ํ ๊ธฐ๋ฅ์ด ์๋ค๋ฉด ์ง์ Hook์ ๋ง๋ค์ด์ ์ฌ์ฉํ ์ ์๋ค.
์ด๊ฒ์ด Custom Hook์ด๋ค.
Custom Hook์ ๋ง๋๋ ์ด์ ๋ ์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ๋ฐ๋ณต์ ์ผ๋ก ์ฌ์ฉ๋๋ ๋ก์ง์ Hook์ผ๋ก ๋ง๋ค์ด ์ฌ์ฌ์ฉํ๊ธฐ ์ํจ์ด๋ค.
Custom Hook์ ๋ง๋ค์ด์ผ ํ๋ ์ํฉ
์์ ์ฝ๋ )
import React, {useState, useEffect} from "react";
function UserStatus(props){
const [isOnline, setIsOnline] = useState(null);
usseEffect(() => {
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 ? '์จ๋ผ์ธ' : '์คํ๋ผ์ธ';
}
//์ฝ๋ ์ฐธ๊ณ
//์ธํ๋ฐ_์ฒ์ ๋ง๋ ๋ฆฌ์กํธ
์ ์ฝ๋๋ UserStatus ๋ผ๋ ์ปดํฌ๋ํธ๋ isOnline ์ด๋ผ๋ State์ ๋ฐ๋ผ์, ์ฌ์ฉ์์ ์ํ๊ฐ ์จ๋ผ์ธ์ธ์ง ์๋์ง๋ฅผ ํ ์คํธ๋ก ๋ณด์ฌ์ฃผ๋ ์ปดํฌ๋ํธ์ด๋ค.
๋ง์ฝ ์จ๋ผ์ธ์ธ ์ฌ๋์ ์ด๋ฆ์ ์ด๋ก์์ผ๋ก ํ์ํ๊ณ ์ถ๋ค๋ฉด?
์ปดํฌ๋ํธ์ ์ด๋ฆ์ UserListItem์ด๋ผ๊ณ ํ๊ณ , ์ฌ๊ธฐ์ ๋น์ทํ ๋ก์ง์ ๋ฃ์ด์ผ ํ๋ค
์๋ ์ฝ๋์ฒ๋ผ ๋ง๋๋ ๊ฒ์ด๋ค.
import React, {useState, useEffect} from "react";
function UserListItem(props){
const [isOnline, setIsOnline] = useState(null);
usseEffect(() => {
function handleStatusChange(status){
setIsOnline(status.isOnline);
}
ServerAPI.subscribeUserStatus(props.user.id, handleStatusChange);
return () => {
ServerAPI.unsubscribeUserStatus(props.user.id, handleStatusChange);
};
});
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.user.name}
</li>
);
}
//์ฝ๋ ์ฐธ๊ณ
//์ธํ๋ฐ_์ฒ์ ๋ง๋ ๋ฆฌ์กํธ
์ค๋ณต๋๋ ๋ก์ง์ ์ฐพ์ Custom Hook์ผ๋ก ์ถ์ถํ๊ฒ ๋ค.
2๊ฐ์ ์๋ฐ์คํฌ๋ฆฝํธ ํจ์์์ ํ๋์ ๋ก์ง์ ๊ณต์ ํ๊ณ ์ถ์ ๋์๋ ์๋ก์ด ํจ์๋ฅผ ํ๋ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ด์ฉํ๋ค.
๋ฆฌ์กํธ ํจ์ ์ปดํฌ๋ํธ์ Hook์ ๋ชจ๋ ํจ์์ด๊ธฐ ๋๋ฌธ์ ๋์ผํ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค.
- ์ด๋ฆ์ด use๋ก ์์ํ๊ณ ๋ด๋ถ์์ ๋ค๋ฅธ Hook์ ํธ์ถํ๋ ํ๋์ ์๋ฐ์คํฌ๋ฆฝํธ ํจ์
import React, {useState, useEffect} from "react";
function useUserStatus(userId){
const [isOnline, setIsOnline] = useState(null);
usseEffect(() => {
function handleStatusChange(status){
setIsOnline(status.isOnline);
}
ServerAPI.subscribeUserStatus(userId, handleStatusChange);
return () => {
ServerAPI.unsubscribeUserStatus(userId, handleStatusChange);
};
});
return isOnline;
}
//์ฝ๋ ์ฐธ๊ณ
//์ธํ๋ฐ_์ฒ์ ๋ง๋ ๋ฆฌ์กํธ
์ด ์ฝ๋๋ ์ค๋ณต๋๋ ๋ก์ง์ useUserStatus ๋ผ๋ Custom Hook์ผ๋ก ์ถ์ถํ ๊ฒ์ด๋ค.
function UserStatus(props){
const isOnline = useUserStatus(props.user.id);
if(isOnline === null){
return '๋๊ธฐ์ค...';
}
return isOnline ? '์จ๋ผ์ธ' : '์คํ๋ผ์ธ';
}
function UserListItem(props){
const isOnline = useUserStatus(props.user.id);
return(
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.user.name}
</li>
);
}
//์ฝ๋ ์ฐธ๊ณ
//์ธํ๋ฐ_์ฒ์ ๋ง๋ ๋ฆฌ์กํธ
์ด ์ฝ๋๋ useUserStatus Custom Hook์ ์ฌ์ฉํ ์ฝ๋์ด๋ค. Custom Hook์ ์ฌ์ฉํ๊ธฐ ์ ์ฝ๋์ ๋์ผํ๊ฒ ์๋ํ๋ค.
๋์์ ๋ณ๊ฒฝ์ด ์๊ณ , ์ค๋ณต๋ ๋ก์ง๋ง์ ์ถ์ถํ์ฌ Custom Hook๋ง์ ๋ง๋ค์๊ธฐ ๋๋ฌธ์ด๋ค.
Custom Hook์ ์ด๋ฆ์ ๊ผญ use๋ก ์์ํด์ผํ๋?
๊ทธ๋ ๋ค. ์ด๊ฑด ์ง์ผ์ผ ํ๋ค.
๋ง์ฝ ์ด๋ฆ์ด use๋ก ์์ํ์ง ์๋๋ค๋ฉด ํน์ ํจ์์ ๋ด๋ถ์์ Hook์ ์ถ์ถํ๋ ์ง ์ ์ ์๊ธฐ ๋๋ฌธ์ Hook์ ๊ท์น ์๋ฐ ์ฌ๋ถ๋ฅผ ํ์ธํ๊ธฐ ํ๋ค๋ค.
๊ฐ์ Custom Hook์ ์ฌ์ฉํ๋ 2๊ฐ์ ์ปดํฌ๋ํธ๋ State๋ฅผ ๊ณต์ ํ๋ ๊ฒ์ธ๊ฐ?
์๋๋ค. Custom Hook์ ๋จ์ํ State์ ์ฐ๊ด๋ ๋ก์ง์ ์ฌ์ฌ์ฉ์ด ๊ฐ๋ฅํ๊ฒ ๋ง๋ ๊ฒ์ด๋ค.
๋ฐ๋ผ์, ์ฌ๋ฌ ๊ฐ์ ์ปดํฌ๋ํธ์์ ํ๋์ Custom Hook์ ์ฌ์ฉํ ๋ ์ปดํฌ๋ํธ ๋ด๋ถ์ ์๋ ๋ชจ๋ State์ effects๋ ์ ๋ถ ๋ถ๋ฆฌ๋์ด ์๋ค.
Custom Hook์ ์ด๋ป๊ฒ State๋ฅผ ๋ถ๋ฆฌํ๋ ๊ฒ์ธ๊ฐ?
๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ ๊ฐ๊ฐ์ Custom Hook ํธ์ถ์ ๋ํด์ ๋ถ๋ฆฌ๋ State๋ฅผ ์ป๊ฒ ๋๊ธฐ ๋๋ฌธ์ด๋ค.
๋ํ, ๊ฐ Custom Hook์ ํธ์ถ๋ ์์ ํ ๋ ๋ฆฝ์ ์ด๋ค.
Hook๋ค ์ฌ์ด์์ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ๋ ๋ฐฉ๋ฒ์ ์๋?
์์ ์ฝ๋ )
const userList = [
{ id: 1, name: 'Inje' },
{ id: 2, name: 'Mike' },
{ id: 3, name: 'Steve' },
];
function ChatUserSelector(props){ //์ปดํฌ๋ํธ.
//ํ์ฌ ์ ํ๋ ์ฌ์ฉ์์ id๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ์ฉ๋.
const [userId, setUserId] = useState(1); //useState Hook์ ์ฌ์ฉํด userId๋ผ๋ State ์์ฑ.
//setUserId ํจ์๋ฅผ ํตํด userId๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค userUserStatus Custom Hook์ ์ด์ ์ ์ ํ๋
//์ทจ์ํ๊ณ ์๋ก ์ ํ๋ ์ฌ์ฉ์์ ์จ๋ผ์ธ ์ฌ๋ถ๋ฅผ ์์๋ด๊ฒ ๋๋ค.
const isUserOnline = useUserStatus(userId); //userId๋ useUserStatus Custom Hook์ ํ๋ผ๋ฏธํฐ๋ก ๋ค์ด๊ฐ.
return(
<>
<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>
</>
);
}
//์ฝ๋ ์ฐธ๊ณ
//์ธํ๋ฐ_์ฒ์ ๋ง๋ ๋ฆฌ์กํธ
์ ์ฝ๋๋ ChatUserSelector ๋ผ๋ ์ปดํฌ๋ํธ๊ฐ ๋์จ๋ค.
์ด ์ปดํฌ๋ํธ๋ select ํ๊ทธ๋ฅผ ํตํด ๋ชฉ๋ก์์ ์ฌ์ฉ์๋ฅผ ์ ํํ ์ ์๊ฒ ํด์ฃผ๋ฉฐ ์ฌ์ฉ์๋ฅผ ์ ํํ ๊ฒฝ์ฐ ํด๋น ์ฌ์ฉ์๊ฐ ์จ๋ผ์ธ์ธ์ง ์๋์ง๋ฅผ ๋ณด์ฌ์ฃผ๊ฒ ๋๋ค.
Hook๋ค ์ฌ์ด์์๋ ์ ์ฝ๋ ์ฃผ์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ๋ค.
๐ฑ๐ป Hooks ์ฌ์ฉํด๋ณด๊ธฐ
๐ค useCounter() Custom Hook ๋ง๋ค๊ธฐ
create react app์ ์ด์ฉํด ๋ง๋ ํ๋ก์ ํธ๋ฅผ ์ฐ๋ค.
useCounter.jsx
//useCounter ์ด๋ฆ์ React Hook์ ๋ง๋ ๋ค.
import React,{useState} from "react";
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];
}
export default useCounter;
useCounter Hook์ ์ด๊ธฐ ์นด์ดํฐ ๊ฐ์ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์์ count ์ด๋ฆ์ state๋ฅผ ์์ฑํ์ฌ ๊ฐ์ ์ ๊ณตํ๊ณ , count ์ฆ๊ฐ ๋ฐ ๊ฐ์๋ฅผ ํธ๋ฆฌํ๊ฒ ํ ์ ์๋๋ก ํจ์๋ฅผ ์ ๊ณตํ๋ Hook์ด๋ค.
๐ค Accommodate ์ปดํฌ๋ํธ ๋ง๋ค๊ธฐ
Accommodaate.jsx
//Accommodate ์ด๋ฆ์ React ํจ์ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ ๋ค.
import React, {useState, useEffect} from "react";
import useCounter from "./useCounter";
const MAX_CAPACITY = 10; //์ต๋ ์นด์ดํธ ๊ฐฏ์ ์์๋ก ์ ์.
function Accommodate(props){
const [isFull, setIsFull] = useState(false);
const [count, increaseCount, decreaseCount] = useCounter(0);
useEffect(() => { //์์กด์ฑ ๋ฐฐ์ด ์๋ ํํ.
//์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ๋ ์งํ์ ํธ์ถ๋๋ฉฐ ์ปดํฌ๋ํธ ์
๋ฐ์ดํธ๋ ๋๋ง๋ค ํธ์ถ.
console.log("----------");
console.log("useEffect() is called");
console.log(`isFull: ${isFull}`);
});
useEffect(() => { //์์กด์ฑ ๋ฐฐ์ด ์๋ ํํ.
//์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ๋ ์งํ์ ํธ์ถ๋๋ฉฐ ์ดํ ์นด์ดํธ ๊ฐ์ด ๋ฐ๋ ๋๋ง๋ค ํธ์ถ.
//์ด๋ ์ฉ๋์ด ๊ฐ๋ ์ฐผ๋์ง ํ์ธํ๋ค. => isFull state์ ์ ์ฅ.
setIsFull(count >=MAX_CAPACITY); //์นด์ดํธ ๊ฐฏ์๊ฐ ์ต๋ ์ฉ๋์ ์ด๊ณผํ๋ฉด ๊ฒฝ๊ณ ๋ฌธ๊ตฌ ํ์๋๋ฉด ์
์ฅ ๋ถ๊ฐ.
console.log(`Current count value: ${count}`);
},[count]);
return (
<div style={{padding:16}}>
<p>{`์ด ${count}๋ช
์์ฉํ์ต๋๋ค.`}</p>
<button onClick={increaseCount} disabled={isFull}>
์
์ฅ
</button>
<button onClick={decreaseCount}>ํด์ฅ</button>
{isFull && <p style={{color:"red"}}>์ ์์ด ๊ฐ๋ ์ฐผ์ต๋๋ค.</p>}
</div>
);
}
export default Accommodate;
Accommodate ์ปดํฌ๋ํธ๋ useCount Hook์ ์ฌ์ฉํ์ฌ count๋ฅผ ๊ด๋ฆฌํ๋ค.
์ด์ ์ค์ ํ๋ฉด์ ๋ ๋๋งํ๊ธฐ ์ํด์ index.js ํ์ผ์ ์์ ํด์ผ ํ๋ค.
์ ์ฅ์ ๋๋ฅด๋ฉด count ๊ฐ์ด 1 ์ฆ๊ฐํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ ์์ด ๊ฐ๋ ์ฐจ๋ฉด isFull ๊ฐ์ด true ๊ฐ ๋์ ์ ์ฅ ๋ฒํผ์ด ๋นํ์ฑํ ๋๋ค.
ํด์ฅ ๋ฒํผ์ ๋๋ฅด๋ฉด count ๊ฐ์ด 1 ๊ฐ์ํ๋ฉด์ isFull๊ฐ์ด false๋ก ๋ณํ๋ค.
์๋ฌด๋ฆฌ ํด์ฅ ๋ฒํผ์ ๋๋ฌ๋ 0 ์ดํ๋ก๋ ๋ณํ์ง ์๋๋ค.
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];
}
Math.max ํจ์๋ฅผ ์ฌ์ฉํ์ฌ count ๊ฐ์ด 0 ์๋๋ก ๋ด๋ ค๊ฐ ์ ์๊ฒ ๋ง๋ค์ด๋จ๋ค.
0์ด ๋๋ฉด ๋ ์ด์ useEffect Hook๋ ํธ์ถ๋์ง ์๋๋ค.