You will learn
- ์ปค์คํ ํ ์ด๋ ๋ฌด์์ด๊ณ ์ด๋ป๊ฒ ์์ฑํ๋์ง
- ์ปดํฌ๋ํธ ๊ฐ ๋ก์ง์ ๊ณต์ ํ๋ ๋ฐฉ๋ฒ
- ์ปค์คํ ํ ๋ช ๋ช ํ๋ ๋ฐฉ๋ฒ๊ณผ ๊ตฌ์กฐ๋ฅผ ์ค๊ณํ๋ ๋ฐฉ๋ฒ
- ์ธ์ ์ ๋ก์ง์ ์ปค์คํ ํ ์ผ๋ก ๋ถ๋ฆฌํด์ผ ํ๋์ง
'์ปค์คํ ํ '์ด๋?
์ปค์คํ ํ ์ ๋ ๊ฐ ์ด์์ ์ปดํฌ๋ํธ์์ ๋๊ฐ์ ๋ฆฌ์กํธ ํ ์ฝ๋๋ฅผ ์ฌ์ฉํ ๋ ๊ทธ๊ฑธ ๋ค๋ฅธ ํ์ผ๋ก ๋ถ๋ฆฌํด ์ฌ์ฌ์ฉ ํ ์ ์๊ฒ ํด์ค๋ค.
const [isOnline, setIsOnline] = useState(true);
useEffect(() => {
function handleOnline() {
setIsOnline(true);
}
function handleOffline() {
setIsOnline(false);
}
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ๋คํธ์ํฌ์ ๊ด๋ จ๋ ๋ธ๋ผ์ฐ์ API๋ฅผ ์ฌ์ฉํด isOnline ์ํ๋ฅผ ๋ณ๊ฒฝํด์ฃผ๋ ์ฝ๋๋ค. ์ด ๋๊ฐ์ ๊ธฐ๋ฅ์ SaveButton์ด๋ผ๋ ์ปดํฌ๋ํธ์ StatusBar ์ปดํฌ๋ํธ์์ ๋๊ฐ์ด ์ฌ์ฉํ ๋ ์ด ์ฝ๋๋ฅผ ์ปค์คํ
ํ
์ผ๋ก ๋ถ๋ฆฌํ ์ ์๋ค.
function useOnlineStatus() {
const [isOnline, setIsOnline] = useState(true);
useEffect(() => {
function handleOnline() {
setIsOnline(true);
}
function handleOffline() {
setIsOnline(false);
}
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
return isOnline;
}
function StatusBar() {
const isOnline = useOnlineStatus();
return <h1>{isOnline ? 'โ
Online' : 'โ Disconnected'}</h1>;
}
์ปค์คํ
ํ
๋ช
๋ช
๊ท์น use
๋ฆฌ์กํธ์ ๋ค์ด๋ฐ ์ปจ๋ฒค์
- ์ปดํฌ๋ํธ : ๋๋ฌธ์๋ก ์์, ์นด๋ฉ์ผ์ด์ค.
StatusBar,SaveButton,HomePage,App๋ฑ - ํ
:
use๋ก ์์, ๊ทธ ์ดํ๋ก๋ ๋๋ฌธ์๋ก ์์ํ๋ ์นด๋ฉ์ผ์ด์ค.useOnlineStatus,useState,useWindowSize๋ฑ
state ์์ฒด๋ฅผ ๊ณต์ ํ๋๊ฒ ์๋๋ค.
function StatusBar() {
const isOnline = useOnlineStatus();
// ...
}
function SaveButton() {
const isOnline = useOnlineStatus();
// ...
}
์์ ์ฝ๋๋ ์๋์ ์์ ํ ๋์ผํ๊ฒ ์๋ํ๋ค.
function StatusBar() {
const [isOnline, setIsOnline] = useState(true);
useEffect(() => {
// ...
}, []);
// ...
}
function SaveButton() {
const [isOnline, setIsOnline] = useState(true);
useEffect(() => {
// ...
}, []);
// ...
}
์ปค์คํ ํ ์ ์ฌ์ฉํ์๋ ํ ์ ์๋ ์คํด
useOnlineStatus์์isOnline์ด๋ผ๋ ์ํ๊ฐ ๊ด๋ฆฌ๋๋ ๊ฒ์ด๊ณ- ๊ทธ state๋ฅผ ๊ฐ ์ปดํฌ๋ํธ๊ฐ ๊ฐ์ ธ์ ์ฌ์ฉํ๋๊ฒ์ด๋ค.
- ์ฆ state๋ ํ๋๋ง ์กด์ฌํ๊ณ ๊ทธ๊ฑธ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๊ฐ ์ฌ๋ฟ์ด๋ค.
๊ทธ๋ฌ๋ ๋๊ฐ์ ์ฝ๋๋ฅผ ๊ฐ ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ๋๊ฒ๊ณผ ๋๊ฐ์ด ์๋ํ๋ค๋ ๊ฒ์ ๊ธฐ์ตํด์ผ ํ๋ค. ๊ฐ ์ปดํฌ๋ํธ์์ ๊ฐ์ useState์ useEffect๋ฅผ ์ฌ์ฉํด ๊ฐ์์ isOnline ์ปดํฌ๋ํธ๋ฅผ ๊ด๋ฆฌํ๋๊ฒ์ฒ๋ผ, ์ปค์คํ
ํ
์ ์ฌ์ฉํ๋ค๋๊ฒ์ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๋ก์ง์ ๊ณต์ ํ๋ค๋๊ฒ์ด์ง ์ํ ์์ฒด๋ฅผ ๊ณต์ ํ๋๊ฒ์ด ์๋๋ค.
ํ ๋ผ๋ฆฌ์ ๋ฐ์ํ ๊ฐ ์ ๋ฌ
export function useChatRoom({ serverUrl, roomId }) {
useEffect(() => {
const options = {
serverUrl: serverUrl,
roomId: roomId
};
const connection = createConnection(options);
connection.connect();
connection.on('message', (msg) => {
showNotification('New message: ' + msg);
});
return () => connection.disconnect();
}, [roomId, serverUrl]);
}
export default function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useChatRoom({
roomId: roomId,
serverUrl: serverUrl
});
return (
<>
<label>
Server URL:
<input value={serverUrl} onChange={e => setServerUrl(e.target.value)} />
</label>
<h1>Welcome to the {roomId} room!</h1>
</>
);
}
์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด useChatRoom์ ์ดํํธ๋ง ๊ฐ์ง๊ณ ์๋ค. useEffect์ useState๊ฐ ์๋ก state๋ฅผ ์ฃผ๊ณ ๋ฐ์ผ๋ฉด์ ์๋ํ ์ ์์๋ฏ ์ปค์คํ
ํ
์ธ useChatRoom๊ณผ useState๋ ๊ฐ์ด ์๋ํ ์ ์๋ค. prop์ธ roomId๋ ๋ง์ฐฌ๊ฐ์ง.
์ปค์คํ ํ ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ ์ ๋ฌํ๊ธฐ
์ง๊ธ์ ์ปค์คํ ํ ์ ์๋ฆผ์ฐฝ์ ๋์ฐ๋ ํจ์๊ฐ ํ๋์ฝ๋ฉ ๋์ด์๋ค.
export function useChatRoom({ serverUrl, roomId }) {
useEffect(() => {
const options = {
serverUrl: serverUrl,
roomId: roomId
};
const connection = createConnection(options);
connection.connect();
connection.on('message', (msg) => {
showNotification('New message: ' + msg);
});
return () => connection.disconnect();
}, [roomId, serverUrl]);
}
๋ง์ฝ์ ์ปดํฌ๋ํธ๋ง๋ค ์ฝ๊ฐ ๋ค๋ฅด๊ฒ ์๋ฆผ์ฐฝ์ ๋์ฐ๊ณ ์ถ๋ค๋ฉด? ๊ทธ๋ ๋ค๋ฉด useChatRoom์ ํ๋์ฝ๋ฉ๋ ๋ถ๋ถ์ ์ปดํฌ๋ํธ๊ฐ ์ ๋ฌํด์ค์ผ ํ๋ค. ๊ทธ๋์ผ ์ปค์คํ
ํ
์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๋ฉด์ ๊ฐ ์ปดํฌ๋ํธ๋ง๋ค ๊ฐ์ ์ํ๋ ์ด๋ฒคํธ ํธ๋ค๋ง ๋ก์ง์ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ปดํฌ๋ํธ๋ก๋ถํฐ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์ ๋ฌ ๋ฐ์ผ๋ฉด ๊ฐ๋จํ์ง๋ง, ์ดํํธ์์ ๋ฐฐ์ ๋๋๋ก ํจ์๋ ๋ ๋๋ง๋ง๋ค ๋ค๋ฅธ ์ฃผ์๊ฐ์ ๊ฐ์ง๊ธฐ ๋๋ฌธ์ ์์กด์ฑ ๋ฐฐ์ด์์ ๋นผ์ผํ๋ค.
export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) {
const onMessage = useEffectEvent(onReceiveMessage);
useEffect(() => {
const options = {
serverUrl: serverUrl,
roomId: roomId
};
const connection = createConnection(options);
connection.connect();
connection.on('message', (msg) => {
onMessage(msg);
});
return () => connection.disconnect();
}, [roomId, serverUrl]); // โ
All dependencies declared
}
์ธ์ ์ปค์คํ ํ ์ ์ฌ์ฉํ ๊น
๋ฐ๋ณต๋ ์ฝ๋๊ฐ ์์๋๋ง๋ค ์ปค์คํ ํ ์ผ๋ก ๋ถ๋ฆฌ ํ ํ์๋ ์์ง๋ง, ์ดํํธ๋ฅผ ์์ฑํด์ผํ ๋๋ง๋ค ์ปค์คํ ํ ์ผ๋ก ๋ถ๋ฆฌํ ๊ฒ์ ๊ณ ๋ คํด๋ณด๋ผ ํ๋ค.(์ฌ์ฌ์ฉ ๋์ง ์๋๋ค ํ๋๋ผ๋ ๋ถ๋ฆฌํด์ผ ํ ๊น?) ์ดํํธ๋ ์ค์ง ๋ฆฌ์กํธ ์ธ๋ถ์ ์ ๊ทผํ ๋๋ง ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์ดํํธ ์ฝ๋๋ฅผ ์ปดํฌ๋ํธ์์ ๋ถ๋ฆฌํ๋ฉด ํจ์ฌ ๊ฐ๋ ์ฑ์ด ๋์์ง๊ธฐ ๋๋ฌธ์ด๋ค.
์์ ๋ฌธ์
3. ์ปค์คํ ํ ๋ถ๋ฆฌํ๊ธฐ
export function useCounter(delay) {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setCount(c => c + 1);
}, delay);
return () => clearInterval(id);
}, [delay]);
return count;
}
์ด ํ
์ ๋ ๊ฐ์ ํ
์ผ๋ก ๋ถ๋ฆฌํ๋ผ๊ณ ํ๋ค. useCounter๋ ์ฃผ์ด์ก๊ณ useInterval์ ์์ฑํด์ผ ํ๋ค.
export function useCounter(delay) {
const [count, setCount] = useState(0);
useInterval(() => {
setCount(c => c + 1);
}, delay);
return count;
}
๋ต์ ์๋์ ๊ฐ๋ค.
export function useInterval(onTick, delay) {
useEffect(() => {
const id = setInterval(onTick, delay);
return () => clearInterval(id);
}, [onTick, delay]);
}
๋๋ useEffectEvent๋ฅผ ์ฌ์ฉํ๋๋ฐ ๋ต์์์๋ onTick๋ ์์กด์ฑ ๋ฐฐ์ด์ ์ถ๊ฐํ๋ค. ์ ๊ทธ๋ฐ์ง ์์ํ๋๋ฐ ๋ฐ๋ก ๋ค์ ๋ฌธ์ ๊ฐ ์ด์ ๊ด๋ จ๋ ๋ฌธ์ ๋ผ๊ณ ํ๋ค.
์๋ฐํ๊ฒ ๋ชจ๋ ๋ ๋๋ง๋ง๋ค ์ดํํธ๊ฐ ์คํ๋์ด๋ ๋ฌธ์ ๋ ์๋ค. ์๋ํ๋ฉด setInterval์ด ๊ณ์ ์๋ก ์ค์ ๋์ด๋ ์ ํํ 1์ด ์ดํ์ counter๊ฐ ์ฆ๊ฐํ๋๊ฒ์ ๋๊ฐ์ผ๋๊น.
4.
export default function Counter() {
const count = useCounter(1000);
useInterval(() => {
const randomColor = `hsla(${Math.random() * 360}, 100%, 50%, 0.2)`;
document.body.style.backgroundColor = randomColor;
}, 2000);
export function useCounter(delay) {
const [count, setCount] = useState(0);
useInterval(() => {
setCount(c => c + 1);
}, delay);
return count;
}
์ด๋ ๊ฒ ๊ฐ์ ๋ค๋ฅธ delay๊ฐ์ ๊ฐ์ง๊ณ useInterval์ ํธ์ถํ๊ณ ์๋ค.
useInterval์ด ์์์์ฒ๋ผ [onTick, delay]๋ฅผ ์์กด์ฑ ๋ฐฐ์ด๋ก ๊ฐ์ง๊ณ ์๋ ๊ฒฝ์ฐ ๋ฐ์ํ๋ ๋ฌธ์ ๋ ๋ฐฐ๊ฒฝ ์์ด ๋ณํ์ง ์๋๊ฒ์ด๋ค.
์ด์ ๋ ๋ฌด์์ผ๊น? 1์ด ๋ง๋ค count๊ฐ์ด ์
๋ฐ์ดํธ ๋๋ฉด์ Counter ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง ๋๋ค. ๊ทธ ๊ฒฐ๊ณผ useInterval()์ ํธ์ถํ๋ฉด์ ๋๊ฒจ์ค ์์ ๋ณ๊ฒฝํ๋ ํ์ดํ ํจ์(useInterval ์์ onTick์ด๋ผ๋ ๋งค๊ฐ๋ณ์๋ก ์ ๋ฌ ๋ฐ๋ ํจ์)๊ฐ ๋ค๋ฅธ ์ฃผ์๊ฐ์ ๊ฐ์ง๊ฒ ๋๊ณ , ๊ทธ ๊ฒฐ๊ณผ ์์ด ๋ฐ๋๋ 2์ด๊ฐ ์ง๋๊ธฐ ์ ์ ๊ณ์ํด์ ํ์ด๋จธ๊ฐ ๋ฆฌ์
๋๊ธฐ ๋๋ฌธ์.
export function useInterval(callback, delay) {
const onTick = useEffectEvent(callback);
useEffect(() => {
const id = setInterval(onTick, delay);
return () => clearInterval(id);
}, [delay]);
}
๊ทธ๋์ ์ด๋ ๊ฒ ์ดํํธ ์ด๋ฒคํธ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
5. ์๊ฐ๋ฆฐ ์์ง์ ๊ตฌํ
๋ง์ฐ์ค๋ฅผ ๋ฐ๋ผ๋ค๋๋ ์ ์ด 5๊ฐ๊ฐ ์์์๋ ๋ถ๊ตฌํ๊ณ ๋ชจ๋ ๋์์ ์์ง์ด๊ธฐ ๋๋ฌธ์ ํ๋๋ก ๋ณด์ธ๋ค.
function useDelayedValue(value, delay) {
// TODO: Implement this Hook
return value;
}
export default function Canvas() {
const pos1 = usePointerPosition();
const pos2 = useDelayedValue(pos1, 100);
const pos3 = useDelayedValue(pos2, 200);
const pos4 = useDelayedValue(pos3, 100);
const pos5 = useDelayedValue(pos3, 50);
return (
<>
<Dot position={pos1} opacity={1} />
<Dot position={pos2} opacity={0.8} />
<Dot position={pos3} opacity={0.6} />
<Dot position={pos4} opacity={0.4} />
<Dot position={pos5} opacity={0.2} />
</>
);
}
export function usePointerPosition() {
const [position, setPosition] = useState({ x: 0, y: 0 });
useEffect(() => {
function handleMove(e) {
setPosition({ x: e.clientX, y: e.clientY });
}
window.addEventListener('pointermove', handleMove);
return () => window.removeEventListener('pointermove', handleMove);
}, []);
return position;
}

