Hook은 함수형 컴포넌트에서 React state와 라이프사이클을 연동(hook into)해주는 함수다. Hook은 class 안에서는 동작하지 않고, 함수형 컴포넌트에서 class 없이 Hook과 React를 사용할 수 있다.
참고링크
class형 컴포넌트에서 지금까지 객체의 구조분해할당을 많이 사용했다.
const data = {id: 1, name: 'dabin'};
const { id, name } = data;
배열도 구조분해할당이 가능하다.
const [a, b, c, d] = [1, 4, 3, 2]
console.log(a, b, c, d) // 1 4 3 2
state Hook도 배열의 구조분해할당이 적용된 것이다.
//useState는 아래 함수와 같은 모양이다.
function useState () {
//code...
return [state, setState]
}
//state Hook 컨벤션
const [state, setState] = useState(initialState);
//이후 return 내에서 state와 setState를 사용하면 된다
const [state, setState] = useState(initialState);
// 안 좋은 예시
const [state, setState] = useState({
color: "blue",
name: "dabin".
})
//좋은 예시
const [color, setColor] = useState('red')
const [name, setName] = useState('dabin')
useState 하나에서 모든 값을 관리하기 보다는, 함께 변경되는 값끼리만 묶어 사용하기를 권장한다. 추가로, state에서 객체를 수정해야 할 때 아래와 같이 새로운 객체를 만들어서 그 객체에 변화를 주는 방식으로 코드가 작성되어야 한다는 점을 기억하자.
const [user, setUser] = useState({name: 'dabin', nickname: 'dabing'})
const onChange = e => {
const { name, value } = e.target;
setUser({
...user,
[name]: value
})
}
useEffect(function);
useEffect는 함수 컴포넌트 내에서 side effects(컴포넌트 안에서 데이터를 가져오거나 구독하고 DOM을 직접 조작하는 작업 등)를 수행할 수 있게 해준다. 즉, class형 컴포넌트에서 사용하던 componentDidMount 나 componentDidUpdate, componentWillUnmount가 통합되었다고 생각하면 된다.
//update가 있을 때마다 실행
useEffect(() => {
console.log("componentDidUpdate")
})
//[] 빈 배열을 두 번째 인자로 넣으면 최초 렌더링시 한 번만 실행
useEffect(() => {
fetch();
}, [])
const fetch = async () => {
const res = fetch('url');
const data = await res.json();
setData(data)
}
//state가 변화되었을 때만 실행
useEffect(() => {
console.log("componentDidUpdate")
}, [state])
모든 useEffect()는 렌더링될 때 실행된다. 만약 렌더링이 될 때가 아닌, 그 이후 특정 시점에 useEffect()를 실행시키고 싶다면 아래와 같이 조건문을 사용해 코드를 짤 수 있다.
//flag가 true일 때만 로직 실행
useEffect(() => {
if(!flag) return;
//logins
}, [])
커스텀 훅을 통해 반복되는 로직을 쉽게 재사용할 수 있다.
fetch 함수가 많이 반복되니 hooks 폴더를 만들고, hook 코드들을 관리할 수 있도록 해보자.
import { useEffect, useState } from "react"
export const useFetch = ({ url, method = "GET" }) => {
const [data, setData] = useState([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState(false)
useEffect(() => {
fetch(url, { method })
.then(res => res.json())
.then(res => {
setLoading(false)
setData(res)
})
.catch(() => setError(true))
}, [url])
return { data, loading, error }
}
custom hooks를 적용해보자.
import { useFetch } from "../hooks";
const API = "http://localhost:8000/products";
function App() {
const { data, loading, error } = useFetch({ url: API, method: "GET" })
if (loading) return <div>Loading...</div>
if (error) return <div>Error!</div>
return <div>Component</div>
}