한 줄 답변
최상위에서만 Hook을 호출해야한다.
💡 반복문, 조건문 혹은 중첩된 합수 내에서 Hook 호출 금지!if (name !== '') {
useEffect(function persistForm() {
localStorage.setItem('formData', name);
});
};
useEffect(function persistForm() {
// 👍 더 이상 첫 번째 규칙을 어기지 않습니다
if (name !== '') {
localStorage.setItem('formData', name);
}
});
오직 React 함수 내에서 Hook을 호출해야 합니다
💡 일반적인 JS 함수에서 호출 금지!1: import React, { useState } from 'react';
2:
3: function Example() {
4: const [count, setCount] = useState(0);
5:
6: return (
7: <div>
8: <p>You clicked {count} times</p>
9: <button onClick={() => setCount(count + 1)}>
10: Click me
11: </button>
12: </div>
13: );
14: }
Line 1 - import useState Hook from react Line 4 - create state variable and the function which can renew the state. In this exercise, count 값 초기화 및 0으로 할당해주었습니다! Line 9: 사용자가 버튼을 누르면 setCount 함수를 호출하여 state 변수를 갱신합니다. 리액트는 새로운 count 변수를 Example 컴포넌트에 넘기며 해당 컴포넌트를 리렌더링 합니다.useEffect
가 하는 일은 무엇일까요?
- React에게 컴포넌트가 렌더링 이후에 어떤 일을 수행해야하는지 말합니다.
- React는 우리가 넘긴 함수를 기억했다가(이 함수를 ‘effect’라고 부릅니다) DOM 업데이트를 수행한 이후에 불러낼 것입니다.
- 이 외에도 데이터를 가져오거나 다른 명령형(imperative) API를 불러내는 일도 할 수 있습니다.
useEffect
를 컴포넌트 안에서 불러내는 이유는 무엇일까요?
- useEffect
를 컴포넌트 내부에 둠으로써 effect를 통해 count
state 변수(또는 그 어떤 prop에도)에 접근할 수 있게 됩니다.
- 함수 범위 안에 존재하기 때문에 특별한 API 없이도 값을 얻을 수 있는 것입니다.
- Hook은 자바스크립트의 클로저를 이용하여 React에 한정된 API를 고안하는 것보다 자바스크립트가 이미 가지고 있는 방법을 이용하여 문제를 해결합니다.
3. useEffect
는 렌더링 이후에 매번 수행되는 걸까요?
- 네, 기본적으로 첫번째 렌더링과 이후의 모든 업데이트에서 수행됩니다. 마운팅과 업데이트라는 방식으로 생각하는 대신 effect를 렌더링 이후에 발생하는 것으로 생각하는 것이 더 쉬울 것입니다. React는 effect가 수행되는 시점에 이미 DOM이 업데이트되었음을 보장합니다.
4. effect에서 함수를 반환하는 이유는 무엇일까요?
- 이는 effect를 위한 추가적인 정리(clean-up) 메커니즘입니다. 모든 effect는 정리를 위한 함수를 반환할 수 있습니다. 이 점이 구독(subscription)의 추가와 제거를 위한 로직을 가까이 묶어둘 수 있게 합니다. 구독(subscription)의 추가와 제거가 모두 하나의 effect를 구성하는 것입니다.
5. React가 effect를 정리(clean-up)하는 시점은 정확히 언제일까요?
- React는 컴포넌트가 마운트 해제되는 때에 정리(clean-up)를 실행합니다. 하지만 위의 예시에서 보았듯이 effect는 한번이 아니라 렌더링이 실행되는 때마다 실행됩니다. React가 다음 차례의 effect를 실행하기 전에 이전의 렌더링에서 파생된 effect 또한 정리하는 이유가 바로 이 때문입니다.
6. 보충자료
https://ko.reactjs.org/docs/hooks-effect.html
- 예시
```jsx
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
```
- 정리(clean-up)가 필요없는 경우에는 어떤 것도 반환하지 않습니다.
Custom Hook
자신만의 Hook을 만들면 컴포넌트 로직을 함수로 뽑아내어 재사용 할 수 있습니다.
예시로 확인하시죠!
DayList.js 단독으로 사용!
// DayList.js
import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
export default function DayList() {
const [days, setDays] = useState([]);
useEffect(() => {
fetch('http://localhost:3001/days')
.then((res) => {
return res.json();
})
.then((data) => {
setDays(data);
});
}, []);
return (
<ul className='list_day'>
{days.map((day) => {
<li key={day.id}>
<Link to={`/day/${day.day}`}>Day {day.day}</Link>
</li>;
})}
</ul>
);
}
DayList.js에서 useFetch.js(커스텀 훅) 사용!
useFetch.js
import { useEffect, useState } from 'react';
export default function useFetch(url) {
const [data, setData] = useState([]);
useEffect(() => {
fetch(url)
.then((res) => {
return res.json();
})
.then((data) => {
setData(data);
});
}, [url]);
return data;
}
DayList.js
import { Link } from 'react-router-dom';
import useFetch from '../hooks/useFetch';
export default function DayList() {
const days = useFetch('http://localhost:3001/days');
return (
<ul className='list_day'>
{days.map((day) => {
<li key={day.id}>
<Link to={`/day/${day.day}`}>Day {day.day}</Link>
</li>;
})}
</ul>
);
}
특정 api를 호출하여 데이터를 불러오는 요청을 할 경우, 커스텀 훅을 통해 코드를 재사용할 수 있다는 장점이 있네요!
여러 컴포넌트에서 커스텀 훅을 통해 편리하게 사용할 수 있겠군요!