๊ฐ๋ฐ์๊ฐ ์ค์ค๋ก ์ปค์คํ ํ Hook์ ์๋ฏธํ๋ฉฐ, Custom Hook์ ์ด์ฉํด ๋ฐ๋ณต๋๋ ๋ก์ง์ ํจ์๋ก ๋ฝ์๋ด์ด ์ฌ์ฌ์ฉํ ์ ์๋ค.
์ฃผ๋ก, ์ฌ๋ฌ url์ fetchํ ๋, ์ฌ๋ฌ input์ ์ํ ์ํ ๋ณ๊ฒฝ ๋ฑ ๋ฐ๋ณต๋๋ ๋ก์ง์ ๋์ผํ ํจ์์์ ์๋ํ๊ฒ ํ๊ณ ์ถ์ ๋ ์ฌ์ฉํ๋ค.
์ด๋, Custom Hook์ ์ด์ฉํ๋ค๋ฉด ์๋์ ์ฅ์ ์ด ์๋ค.
//FriendStatus : ์น๊ตฌ๊ฐ online์ธ์ง offline์ธ์ง returnํ๋ ์ปดํฌ๋ํธ
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
//FriendListItem : ์น๊ตฌ๊ฐ online์ผ ๋ ์ด๋ก์์ผ๋ก ํ์ํ๋ ์ปดํฌ๋ํธ
function FriendListItem(props) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}
์์ ์์์์ FriendStatus
์ปดํฌ๋ํธ๋ ์ฌ์ฉ์๋ค์ด ์จ๋ผ์ธ์ธ์ง ์คํ๋ผ์ธ์ธ์ง ํ์ธํ๊ณ , FriendListItem
์ปดํฌ๋ํธ๋ ์ฌ์ฉ์๋ค์ ์ํ์ ๋ฐ๋ผ ์จ๋ผ์ธ์ด๋ผ๋ฉด ์ด๋ก์์ผ๋ก ํ์ํ๋ ์ปดํฌ๋ํธ์ด๋ค.
์ด ๋ ์ปดํฌ๋ํธ๋ ์ ํํ๊ฒ ๋๊ฐ์ด ์ฐ์ด๋ ๋ก์ง์ด ์กด์ฌํ๊ณ ์๋๋ฐ,์ด ๋ก์ง์ ๋นผ๋ด์ ๋ ์ปดํฌ๋ํธ์์ ๊ณต์ ํ๊ธฐ ์ํด Custom Hook์ ์ฌ์ฉํด๋ณด์.
๋จผ์ , ๋์ผํ๊ฒ ์ฌ์ฉ๋๊ณ ์๋ ๋ก์ง์ ๋ถ๋ฆฌํ๋ค.
์ด๋, Custom Hook์ ์ ์ํ๋ ๋ฐ ์๋์ ๊ฐ์ ์ผ์ข ์ ๊ท์น์ด ์กด์ฌํ๋ค.
Custom Hook์ use
๋ก ์์ํ๋ JavaScript ํจ์๋ก, ๋ค๋ฅธ Hook(ex.useState
)์ ํธ์ถํ ์ ์๋ค.(์ผ๋ฐ ํจ์์์๋ ๋ถ๊ฐ๋ฅ)
ํ๋ก์ ํธ ๋ด์ Hooks ๋๋ ํ ๋ฆฌ์ Custom Hook์ ์์น์ํจ๋ค.
ํจ์๋ ์กฐ๊ฑด๋ถ ํจ์๊ฐ ์๋์ด์ผ ํ๋ค.
์ฆ, return ๊ฐ์ด ์กฐ๊ฑด๋ถ๊ฐ ์๋์ด์ผ ํ๋ค.
์์์์๋ Custom Hook์ ์ด๋ฆ์ useFriendStatus
๋ก ์ค์ ํ๋ค.
function useFriendStatus(friendID) {// useFriendStatus
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
์์์ ์ถ์ถํ Custom Hook์ ์ ์ฉํ๋ฉด, ์๋์ ๊ฐ์ด ์์ฑํ ์ ์๋ค.
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
const isOnline = useFriendStatus(props.friend.id);
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}
๊ธฐ์กด์ ์ฝ๋์ ๋น๊ตํ์ ๋, ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ ์ง๊ด์ ์ผ๋ก ํ์ธํ ์ ์๋ค.
๋จ, ๊ฐ์ Custom Hook์ ์ฌ์ฉํ๋ค๊ณ ํ๋๋ผ๋ ๋ ์ปดํฌ๋ํธ๋ ๊ฐ์ ๋ก์ง๋ง ๊ณต์ ํ ๋ฟ, state๋ ์ปดํฌ๋ํธ ๋ด์์ ๋ ๋ฆฝ์ ์ผ๋ก ์ ์๋์ด ์์ผ๋ฏ๋ก ๊ฐ์ state๋ฅผ ๊ณต์ ํ๋ ๊ฒ์ ์๋๋ค.
const useFetch = ( initialUrl:string ) => {
const [url, setUrl] = useState(initialUrl);
const [value, setValue] = useState('');
const fetchData = () => axios.get(url).then(({data}) => setValue(data));
useEffect(() => {
fetchData();
},[url]);
return [value];
};
export default useFetch;
[์ฝ๋] ์ฌ๋ฌ url์ fetchํ ๋ ์ธ ์ ์๋ useFetch
Hook
import { useState, useCallback } from 'react';
function useInputs(initialForm) {
const [form, setForm] = useState(initialForm);
// change
const onChange = useCallback(e => {
const { name, value } = e.target;
setForm(form => ({ ...form, [name]: value }));
}, []);
const reset = useCallback(() => setForm(initialForm), [initialForm]);
return [form, onChange, reset];
}
export default useInputs;
[์ฝ๋] ์ฌ๋ฌ input์ ์ํ ์ํ ๋ณ๊ฒฝ์ ํ ๋ ์ธ ์ ์๋ useInputs
Hooks
// App.js
import useFetch from "./util/useFetch";
import "./styles.css";
//useFetch, useInput, useForm : custom hook
export default function App() {
const fetchData = useFetch("data.json");
return (
<div className="App">
<h1>To do List</h1>
<div className="todo-list">
{fetchData &&
fetchData.todo.map((el) => {
return <li key={el.id}>{el.todo}</li>;
})}
</div>
</div>
);
}
// .util/useFetch.js
import { useEffect, useState } from "react";
const useFetch = (fetchUrl) => {
const [data, setData] = useState();
useEffect(() => {
fetch(fetchUrl, {
headers: {
"Content-Type": "application/json",
Accept: "application/json"
}
})
.then((response) => {
return response.json();
})
.then((myJson) => {
setData(myJson);
})
.catch((error) => {
console.log(error);
});
}, [fetchUrl]);
//loading, error
return data;
};
export default useFetch;
[๊ทธ๋ฆผ]ํ์ผ list
[๊ทธ๋ฆผ]๊ฒฐ๊ณผ ํ๋ฉด
// App.js
import { useState } from "react";
import useInput from "./util/useInput";
import Input from "./component/Input";
import "./styles.css";
export default function App() {
const [fistValue, firstBind, firstReset] = useInput("");
const [lastValue, lastBind, lastReset] = useInput("");
const [nameArr, setNameArr] = useState([]);
const handleSubmit = (e) => {
e.preventDefault();
setNameArr([...nameArr, `${fistValue} ${lastValue}`]);
firstReset();
lastReset();
};
return (
<div className="App">
<h1>Name List</h1>
<div className="name-form">
<form onSubmit={handleSubmit}>
<Input labelText={"์ฑ"} value={firstBind} />
<Input labelText={"์ด๋ฆ"} value={lastBind} />
<button>์ ์ถ</button>
</form>
</div>
<div className="name-list-wrap">
<div className="name-list">
{nameArr.map((el, idx) => {
return <p key={idx}>{el}</p>;
})}
</div>
</div>
</div>
);
}
// .component/Input.js
function Input({ labelText, value }) {
return (
<div className="name-input">
<label>{labelText}</label>
<input {...value} type="text" />
</div>
);
}
export default Input;
// .util/useInput.js
import { useState } from "react";
function useInput(initialValue) {
const [value, setValue] = useState(initialValue);
const bind = {
value,
onChange: (e) => {
setValue(e.target.value);
}
};
const reset = () => {
setValue(initialValue);
};
//return ํด์ผ ํ๋ ๊ฐ์ ๋ฐฐ์ด ํํ์ ๊ฐ
return [value, bind, reset];
}
export default useInput;
[๊ทธ๋ฆผ]ํ์ผ list
[๊ทธ๋ฆผ]๊ฒฐ๊ณผ ํ๋ฉด
Reference:
์ฝ๋์คํ ์ด์ธ