: 개발자가 스스로 커스텀한 훅을 의미하며, 이를 이용해 반복되는 로직을 함수로 뽑아내어 재사용 할 수 있다.
use
를 붙이는 것이 규칙이다.// src/App.js
import "./styles.css";
import { useEffect, useState } from "react";
export default function App() {
const [data, setData] = useState();
useEffect(() => {
fetch("data.json", {
headers: {
"Content-Type": "application/json",
Accept: "application/json"
}
})
.then((response) => {
return response.json();
})
.then((myJson) => {
setData(myJson);
})
.catch((error) => {
console.log(error);
});
}, []);
return (
<div className="App">
<h1>To do List</h1>
<div className="todo-list">
{data &&
data.todo.map((el) => {
return <li key={el.id}>{el.todo}</li>;
})}
</div>
</div>
);
}
// src/utill/hooks.js
//app.js에서 함수를 가져와서 Custom hook을 만들어 봅시다.
//hooks.js의 이름도 알맞게 바꿔주세요.
const hooks = (fetchUrl) => {};
export default hooks;
useEffect
hook을 이용한 로직은 반복되는 로직이 많다.
특히 API를 통해 데이터를 받아와 처리하는 로직은 반복적일 수 밖에 없다.
이러한 로직을 custom hook으로 만들어 분리해보자.
// src/util/useFetch.js
// hook.js -> useFetch.js 파일 이름 변경
import { useEffect, useState } from "react";
const useFetch = (fetchUrl) => {
const [value, setValue] = useState();
useEffect(() => {
fetch(fetchUrl, {
headers: {
"Content-Type": "application/json",
Accept: "application/json"
}
})
.then((response) => {
return response.json();
})
.then((myJson) => {
setValue(myJson);
})
.catch((error) => {
console.log(error);
});
}, [fetchUrl]);
return value;
};
export default useFetch;
// src/App.js
import "./styles.css";
import useFetch from "./util/useFetch";
export default function App() {
const data = useFetch("data.json");
return (
<div className="App">
<h1>To do List</h1>
<div className="todo-list">
{data &&
data.todo.map((el) => {
return <li key={el.id}>{el.todo}</li>;
})}
</div>
</div>
);
}
// src/App.js
import { useState } from "react";
import useInput from "./util/useInput";
import Input from "./component/Input";
import "./styles.css";
export default function App() {
//input에 들어가는 상태값 및 로직을 custom hook으로 만들어봅니다.
//until 폴더의 useInput.js 파일이 만들어져 있습니다.
const [firstNameValue, setFirstNameValue] = useState("");
const [lastNameValue, setLastNameValue] = useState("");
const [nameArr, setNameArr] = useState([]);
const handleSubmit = (e) => {
e.preventDefault();
setNameArr([...nameArr, `${firstNameValue} ${lastNameValue}`]);
};
return (
<div className="App">
<h1>Name List</h1>
<div className="name-form">
<form onSubmit={handleSubmit}>
<div className="name-input">
<label>성</label>
<input
value={firstNameValue}
onChange={(e) => setFirstNameValue(e.target.value)}
type="text"
/>
</div>
<div className="name-input">
<label>이름</label>
<input
value={lastNameValue}
onChange={(e) => setLastNameValue(e.target.value)}
type="text"
/>
</div>
<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>
);
}
// src/util/useInput.js
//이 곳에 input custom hook을 만들어 보세요.
//return 해야 하는 값은 배열 형태의 값이어야 합니다.
function useInput() {
return [];
}
export default useInput;
// src/component/Input.js
function Input() {
//input을 컴포넌트로 만들어봅니다.
//input도 컴포넌트도 만들게 되면 로직을 조금 더 고민을 해야 합니다.
//고민을 한 번 해보고, 시도 해보세요!
}
export default Input;
input
또한 반복적으로 사용되는 로직을 가지고 있는 컴포넌트이다.
이런 식으로 앱 내에 반복적으로 사용되고 관리되는 로직은 많다.
이런 컴포넌트 또한 custom hook을 이용하여 로직을 분리하여 관리할 수 있다.
App
컴포넌트에 들어 있는 input Input
컴포넌트로 바꾼 후, custom hook을 이용하여 input 로직을 분리해보자.
// src/App.js
import { useState } from "react";
import useInput from "./util/useInput";
import shortid from "shortid";
import Input from "./component/Input";
import "./styles.css";
export default function App() {
//input에 들어가는 상태값 및 로직을 custom hook으로 만들어봅니다.
//until 폴더의 useInput.js 파일이 만들어져 있습니다.
const [nameArr, setNameArr] = useState([]);
const [firstBind, firstReset] = useInput("");
const [lastBind, lastReset] = useInput("");
const handleSubmit = (e) => {
e.preventDefault();
let userName = {
id: shortid.generate(),
first: firstBind.value,
last: lastBind.value
};
setNameArr([...nameArr, userName]);
firstReset();
lastReset();
};
return (
<div className="App">
<h1>Name List</h1>
<div className="name-form">
<form onSubmit={handleSubmit}>
<Input label={"성"} {...firstBind} />
<Input label={"이름"} {...lastBind} />
<button>제출</button>
</form>
</div>
<div className="name-list-wrap">
<div className="name-list">
{nameArr.map((el) => {
return (
<p key={el.id}>
{el.first}
{el.last}
</p>
);
})}
</div>
</div>
</div>
);
}
// src/util/useInput.js
//이 곳에 input custom hook을 만들어 보세요.
//return 해야 하는 값은 배열 형태의 값이어야 합니다.
import { useCallback, useState } from "react";
function useInput(initialValue) {
const [value, setValue] = useState(initialValue);
const reset = useCallback(() => setValue(initialValue), [initialValue]);
const bind = {
value,
onChange: useCallback((e) => {
const { value } = e.target;
setValue(value);
}, [])
};
return [bind, reset];
}
export default useInput;
// src/component/Input.js
function Input({ label, value, onChange }) {
//input을 컴포넌트로 만들어봅니다.
//input도 컴포넌트도 만들게 되면 로직을 조금 더 고민을 해야 합니다.
//고민을 한 번 해보고, 시도 해보세요!
return (
<div className="name-input">
<label>{label}</label>
<input value={value} onChange={onChange} type="text" />
</div>
);
}
export default Input;