custom hook실습
custom hook을 이용하여 useEffect 로직 분리하기
hook.js
import { useEffect, useState } from "react";
const useFetchData = (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]);
return data;
};
export default useFetchData;
App.js
import "./styles.css";
import useFetchData from "./util/hooks";
export default function App() {
const data = useFetchData("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>
);
}
App.js는 처음 렌더링될때 한번만 실행이되고
hook.js에는 fetchUrl이 바뀔때마다 렌더링이 되었다.
그 이유는 fetchUrl이 하드코딩되어 있기 때문이다.
fetchUrl의 값은 "data.json"으로 고정되어 있고, fetchUrl이 다른 값으로 변경될 가능성이 없기 때문에
useEffect 함수의 의존성 배열이 빈 배열로 설정된다.
hook.js에서 fetchUrl이 변경될 수 있는 이유는 useFetchData 훅의 파라미터로 fetchUrl이 전달되기 때문이다.
fetchUrl은 useFetchData의 인자로 전달되므로, 해당 값이 변경될 때마다 useFetchData 훅을 호출할 때마다 다른 URL로 API 요청을 보내게 된다.
fetchUrl이 변경될 때마다 해당 함수를 호출하여 새로운 데이터를 가져오기 위해서다.
custom hook을 이용하여 input 로직 분리하기
util / useInput.js
import { useState } from "react";
function useInput() {
const [value, setValue] = useState("");
const handleChange = (e) => {
setValue(e.target.value);
};
const clearValue = () => {
setValue("");
};
return [value, handleChange, clearValue];
}
export default useInput;
compenent / input.js
import React from "react";
function Input({ label, value, onChange }) {
return (
<div className="name-input">
<label>{label}</label>
<input value={value} onChange={onChange} type="text" />
</div>
);
}
export default Input;
App.js
import { useState } from "react";
import useInput from "./util/useInput.js";
import Input from "./component/Input";
import "./styles.css";
export default function App() {
const [nameArr, setNameArr] = useState([]);
const [firstNameValue, handleFirstNameChange, clearFirstName] = useInput("");
const [lastNameValue, handleLastNameChange, clearLastName] = useInput("");
const handleSubmit = (e) => {
e.preventDefault();
setNameArr([...nameArr, `${firstNameValue} ${lastNameValue}`]);
clearFirstName();
clearLastName();
};
return (
<div className="App">
<h1>Name List</h1>
<div className="name-form">
<form onSubmit={handleSubmit}>
<Input label="성" value={firstNameValue} onChange={handleFirstNameChange} />
<Input label="이름" value={lastNameValue} onChange={handleLastNameChange} />
<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>
);
}
useInput 커스텀 훅에서 입력값과 관련된 상태 및 함수를 관리하고,
Input 컴포넌트에서는 해당 상태와 함수를 props로 전달받아 사용하도록 구현하였다.
그리고 마지막으로 App 컴포넌트에서는 useInput 커스텀 훅을 이용하여 각각의 입력값 상태와 관련된 함수를 선언하여 사용하도록 구현하였다.
이렇게 하면, 입력값과 관련된 로직을 useInput 커스텀 훅에서 분리할 수 있고,
이를 이용하여 각각의 입력값 상태와 관련된 함수를 손쉽게 재사용 할 수 있다.
e.preventDefault()는 폼의 제출 버튼을 눌렀을 때 페이지가 다시 로드되는 것을 막는다.
이후 setNameArr, clearFirstName, clearLastName 함수를 호출하여 상태를 업데이트하고 초기화