일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- eslint
- VanillaJS
- 코딩테스트
- 그리디
- useMemo
- React.memo
- VanillJS
- Custom Hook
- Permutations
- 완전탐색
- await
- venv
- python
- BFS
- useState
- canvas
- useEffect
- 프로그래머스
- webpack
- web
- prettier
- 비동기
- Hook
- 코테
- useCallback
- 환경설정
- pjax
- react internals
- seo
- react
- Today
- Total
Amada Coding Club
[React Hook] 리액트 Hook 총정리(3) - useEffect 본문
2023.01.20 - [Front-End/React] - [React Hook] 리액트 Hook 총정리(2) - useState
이번 시간엔 함수 컴포넌트에서 사이드 이펙트를 수행할 수 있는 useEffect에 대해 알아보자
우선 사이드 이펙트에 대해 간략하게 알아보자
사이드 이펙트란?
side effect는 컴포넌트가 렌더링된 이후에 비동기적으로 처리되어야 하는 부수적인 효과를 말한다.
예를 들어 데이터 가져오기가 있다. 데이터를 가져오는데 비동기적으로 처리해야 하는 이유는 데이터를 가지고 오는데 실패하거나 시간이 오래 걸리더라도 이에 상관없이 화면을 렌더링해 사용자가 화면을 기다리는 시간을 최소화할 수 있다는 점에서 비동기적으로 실행한다.
이외의 사이드 이펙트로는 구독 설정하기(외부 API 연결), 수동으로 컴포넌트의 DOM을 수정하는 등의 동작이 있다.
이제 다시 useEffect로 돌아가자
useEffect의 사이드 이펙트는 크게 두 가지로 나뉜다.
1. 정리가 필요한 사이드 이펙트
2. 정리가 필요없는 사이드 이펙트
이때 정리란 사이드 이펙트를 실행하고 나서 추가적으로 실행해야하는 작업(API를 통해 값을 받아온 후 이 연결을 해제하는 작업 등)을 뜻한다.
먼저 정리가 필요없는 사이드 이펙트를 생각해보자
정리가 필요없는 사이드 이펙트
먼저 코드를 먼저 보자
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
우선 useEffect 안에 title을 수정하는 작업은 이후 추가적으로 정리하는 작업이 필요없다.
useEffect는 렌더링 이후 어떤 함수(effect라고 부름)가 실행되어야 하는지 알려준다. useEffect안에 effect를 넣어주면 리액트는 해당 이펙트를 기억했다가 DOM이 업데이트 되고 해당 이펙트를 수행하게 된다. 이펙트는 위와 같이 문서의 타이틀을 지정하는 함수뿐만 아니라 데이터를 가지고 오고 API를 호출하는 다양한 함수를 지정할 수 있다.
그래서 위의 경우에는 버튼을 클릭했을 때 useState의 count값이 변경되고 그리고 useEffect안에 있는 이펙트가 실행되는 경우이다.
보통 useEffect는 컴포넌트 안에 들어가 있다. 그 이유는 useEffect를 컴포넌트 안에 둠으로써 그 컴포넌트의 props나 state값을 특별한 API없이 바로 사용할 수 있어 편리하기 때문에 컴포넌트 안에 둔다.
위 useEffect는 렌더링이 되고 나서 DOM이 업데이트될 때마다 이펙트가 실행된다. 만약 렌더링될 때 한 번만 실행되는 걸 원하거나 특정 값이 바꼈을 때 렌더링되는 걸 원한다면 그렇게 만들 수 있는 방법이 있다. 그건 아래 참고.
이제는 정리가 필요한 사이드 이펙트이다
정리가 필요한 사이드 이펙트
다시 코드를 먼저 보자
import React, { useState, useEffect } from 'react';
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
// effect 이후에 어떻게 정리(clean-up)할 것인지 표시합니다.
return function cleanup() {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
위 컴포넌트는 친구의 온라인 상태를 구독할 수 있는 모듈이다.
useEffect에서 정리하는 함수(cleanup이라 한다)는 반환을 통해 구현할 수 있다. 이 함수는 컴포넌트가 언마운트(사라질 때)될 때나 effect가 종료될 때 실행되어 기존에 실행했던 effect를 정리하는 작업을 수행한다. 위에 경우에는 API를 구독하는 이펙트를 실행하고 나서 다음 이펙트가 실행되기 전에 cleanup함수를 실행한다. 이를 통해 이펙트를 통해 받아온 값이 충돌하는 것을 막을 수 있다.
클래스형 컴포넌트에서 위 컴포넌트를 구현하기 위해선 effect와 cleanup함수를 다른 메소드로 구현해야한다. 두 개가 다른 메소드로 분리되어있기 때문에 가독성을 떨어트린다는 문제가 있다. 그러나 useEffect를 사용하게되면 위와 같이 구독과 해제를 붙여놓기 때문에 코드를 이해하기 쉬워진다.
팁
만약에 useEffect를 통해 다양한 이펙트를 등록시키고 싶다면 여러개의 useEffect를 사용해도 무방하다.
-> 이를 multiple effect라 한다
function FriendStatusWithCounter(props) {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
//이렇게 역할이 다른 두 코드를 나누어 사용해도 무방하다
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);
};
});
// ...
}
두 번째로 useEffect를 사용하면 DOM이 업데이트될 때마다 이펙트가 실행된다고 했다.
만약, 이펙트를 특정 값이 변경될 때만 실행되도록 하기 위해선 어떻게 해야할까?
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
}, [props.friend.id]);
위와 같이 useEffect의 두 번째 인자로 배열 값을 넣어주면 해당 값이 변할 때만 이펙트가 실행된다.
만약 컴포넌트가 렌더링 될때 한 번만 이펙트를 실행하고 싶다면 빈 배열을 넣으면 된다. 이때 cleanup 함수는 컴포넌트가 언마운트될 때 실행된다.
그래도 이제 어느정도 useEffect에 대해 이해한 것 같다.
다음은 hook 규칙에 대해 알아보자
2023.01.28 - [Front-End/React] - [React Hook] 리액트 Hook 총정리(4) - Hook 사용 규칙, Hook 제작방법
참조
'Front-End > React' 카테고리의 다른 글
[React Hook] 리액트 Hook 총정리(5) - useMemo useCallback (React.memo) (0) | 2023.01.28 |
---|---|
[React Hook] 리액트 Hook 총정리(4) - Hook 사용 규칙, Hook 제작방법 (0) | 2023.01.28 |
[React Hook] 리액트 Hook 총정리(2) - useState (0) | 2023.01.20 |
[React Hook] 리액트 Hook 총정리(1) - Hook이란? (0) | 2023.01.17 |
[React-Dropzone] TypeScript 사용시 acceptedFiles 에서 발생하는 오류 관련 및 해결 (0) | 2023.01.08 |