useEffect의 cleanup함수에 대해 알아보자 ❕
지난 포스터와 같이 useEffect에서 cleanup 함수를 사용해야 할 때가 있다. cleanup 함수가 필요한 경우와 동작 과정이 어떻게 되는지 정리하려고 한다.
1. useEffect 란?
useEffect는 컴포넌트가 렌더링 될 때마다 특정 작업(Side effect)을 실행할 수 있도록 하는 리액트 Hook이다. 컴포넌트가 mount, unmount, update됐을 때 특정 작업을 실행시킬 수 있다.
기본 형태는 useEffect(setup, dependencies?)
로 사용되며, dependencies는 생략할 수 있다. dependencies에 빈 배열([ ])을 입력한 경우 컴포넌트가 처음 mount되었을 때 한번 호출되고, dependencies에 특정 값을 넣은 경우 이 값들이 변경될 때마다 호출된다.
다음과 같이 useEffect를 작성했다면, 컴포넌트가 처음 mount되었을 때 "hello"가 출력되고 상태값 dep
가 변경될 때마다 "안녕"이 출력된다.
useEffect(() => {
console.log("hello")
}, [])
useEffect(() => {
console.log("안녕")
}, [dep])
2. cleanup함수란?
useEffect에서는 함수를 반환할 수 있는데 이를 cleanup 함수라고 부른다. cleanup 함수를 사용하면 컴포넌트가 unmount될 때 or 특정 값이 업데이트되기 직전에 실행할 작업을 지정할 수 있다.
즉, cleanup 함수는 다음과 같이 상황에서 실행된다.
- dependencies가 빈 배열([ ])인 경우, 컴포넌트가 unmount될 때
- dependencies에 특정 값을 설정한 경우, 해당 값들이 업데이트되기 직전
(2) 의 예로, dependencies에 상태값 count를 넣고 cleanup 함수가 언제 실행되는지 확인해봤다.
'더하자'라는 버튼을 클릭했을 때, count가 1 증가하도록 했다.
import { useEffect, useState } from "react"
export function Test() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(count);
return () => console.log("cleanup : " + count); // cleanup 함수
}, [count])
const handleActionClick = () => {
setCount(prev => prev + 1)
}
return (
<>
<button onClick={() => handleActionClick()}>
더하자
</button>
</>
)
}

순서를 보면, count가 변경되기 전에 cleanup함수가 실행되어 `cleanup : count`가 출력되고, 그 후 변경된 `count+1`가 출력된다.
따라서 특정 값이 변경되기 전에 어떠한 작업을 수행하고 싶다면 cleanup 함수로 등록해 사용할 수 있다.
3. useEffect에서 cleanup 함수가 필요한 경우
React 공식문서에는 `setInterval()`, `window.addEventListener()` 등과 같이 React에 의해 제어되지 않는 작업에서 cleanup 함수를 사용하라고 한다.

예제

'버튼 활성화'을 클릭해 '더하기' 버튼을 활성화시키고, '더하기' 버튼을 클릭해 count를 증가시키려고 한다.
(여기서 '더하기'의 클릭 이벤트는 addEventListener()로 등록해 사용한다)
import { useEffect, useState } from "react"
export function Test() {
const [isActive, setIsActive] = useState(false); // 버튼 활성화 여부
const [count, setCount] = useState(0);
useEffect(() => {
if(!isActive) {
return
}
document.getElementById("add-button").addEventListener('mousedown', handleActionClick);
}, [isActive])
const handleActionClick = () => {
setCount(prev => prev + 1)
}
const handleChangeButtonActive = () => {
setIsActive(!isActive);
}
return (
<>
<div>
<button onClick={() => handleChangeButtonActive()}>
{isActive ?
<span>버튼 비활성화</span>
:
<span>버튼 활성화</span>
}
</button>
</div>
<div>
<button id="add-button" disabled={!isActive}>
더하기
</button>
</div>
<div>{count}</div>
</>
)
}


하지만 의도한 대로 동작하지 않는다. 일정하게 1씩 증가되지 않고, 버튼이 활성화 될 때(n)마다 count 값이 n+1씩 증가된다. 이는 isActive가 변경 될 때마다 useEffect의 document.getElementById("add-button").addEventListener('mousedown', handleActionClick)
가 실행되고 이벤트리스너가 여러번 등록되어 발생하는 문제이다.
이 문제를 useEffect의 cleanup함수로 해결할 수 있다.
import { useEffect, useState } from "react"
export function Test() {
const [isActive, setIsActive] = useState(false);
const [count, setCount] = useState(0);
useEffect(() => {
if(!isActive) {
return
}
document.getElementById("add-button").addEventListener('mousedown', handleActionClick);
// cleanup : 이벤트리스너 제거
return () => document.getElementById("add-button").removeEventListener('mousedown', handleActionClick);
}, [isActive])
const handleActionClick = () => {
setCount(prev => prev + 1)
}
const handleChangeButtonActive = () => {
setIsActive(!isActive);
}
return (
<>
<div>
<button onClick={() => handleChangeButtonActive()}>
{isActive ?
<span>버튼 비활성화</span>
:
<span>버튼 활성화</span>
}
</button>
</div>
<div>
<button id="add-button" disabled={!isActive}>
더하기
</button>
</div>
<div>{count}</div>
</>
)
}

이제 버튼을 여러번 활성화시켜도 일정하게 1씩 증가하게 된다.
참고자료 😃
https://legacy.reactjs.org/docs/hooks-effect.html
https://react.dev/reference/react/useEffect#useeffect
'React' 카테고리의 다른 글
[React] 특정 영역의 외부 클릭 감지하기 (0) | 2024.03.10 |
---|
useEffect의 cleanup함수에 대해 알아보자 ❕
지난 포스터와 같이 useEffect에서 cleanup 함수를 사용해야 할 때가 있다. cleanup 함수가 필요한 경우와 동작 과정이 어떻게 되는지 정리하려고 한다.
1. useEffect 란?
useEffect는 컴포넌트가 렌더링 될 때마다 특정 작업(Side effect)을 실행할 수 있도록 하는 리액트 Hook이다. 컴포넌트가 mount, unmount, update됐을 때 특정 작업을 실행시킬 수 있다.
기본 형태는 useEffect(setup, dependencies?)
로 사용되며, dependencies는 생략할 수 있다. dependencies에 빈 배열([ ])을 입력한 경우 컴포넌트가 처음 mount되었을 때 한번 호출되고, dependencies에 특정 값을 넣은 경우 이 값들이 변경될 때마다 호출된다.
다음과 같이 useEffect를 작성했다면, 컴포넌트가 처음 mount되었을 때 "hello"가 출력되고 상태값 dep
가 변경될 때마다 "안녕"이 출력된다.
useEffect(() => {
console.log("hello")
}, [])
useEffect(() => {
console.log("안녕")
}, [dep])
2. cleanup함수란?
useEffect에서는 함수를 반환할 수 있는데 이를 cleanup 함수라고 부른다. cleanup 함수를 사용하면 컴포넌트가 unmount될 때 or 특정 값이 업데이트되기 직전에 실행할 작업을 지정할 수 있다.
즉, cleanup 함수는 다음과 같이 상황에서 실행된다.
- dependencies가 빈 배열([ ])인 경우, 컴포넌트가 unmount될 때
- dependencies에 특정 값을 설정한 경우, 해당 값들이 업데이트되기 직전
(2) 의 예로, dependencies에 상태값 count를 넣고 cleanup 함수가 언제 실행되는지 확인해봤다.
'더하자'라는 버튼을 클릭했을 때, count가 1 증가하도록 했다.
import { useEffect, useState } from "react"
export function Test() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(count);
return () => console.log("cleanup : " + count); // cleanup 함수
}, [count])
const handleActionClick = () => {
setCount(prev => prev + 1)
}
return (
<>
<button onClick={() => handleActionClick()}>
더하자
</button>
</>
)
}

순서를 보면, count가 변경되기 전에 cleanup함수가 실행되어 cleanup : count
가 출력되고, 그 후 변경된 count+1
가 출력된다.
따라서 특정 값이 변경되기 전에 어떠한 작업을 수행하고 싶다면 cleanup 함수로 등록해 사용할 수 있다.
3. useEffect에서 cleanup 함수가 필요한 경우
React 공식문서에는 setInterval()
, window.addEventListener()
등과 같이 React에 의해 제어되지 않는 작업에서 cleanup 함수를 사용하라고 한다.

예제

'버튼 활성화'을 클릭해 '더하기' 버튼을 활성화시키고, '더하기' 버튼을 클릭해 count를 증가시키려고 한다.
(여기서 '더하기'의 클릭 이벤트는 addEventListener()로 등록해 사용한다)
import { useEffect, useState } from "react"
export function Test() {
const [isActive, setIsActive] = useState(false); // 버튼 활성화 여부
const [count, setCount] = useState(0);
useEffect(() => {
if(!isActive) {
return
}
document.getElementById("add-button").addEventListener('mousedown', handleActionClick);
}, [isActive])
const handleActionClick = () => {
setCount(prev => prev + 1)
}
const handleChangeButtonActive = () => {
setIsActive(!isActive);
}
return (
<>
<div>
<button onClick={() => handleChangeButtonActive()}>
{isActive ?
<span>버튼 비활성화</span>
:
<span>버튼 활성화</span>
}
</button>
</div>
<div>
<button id="add-button" disabled={!isActive}>
더하기
</button>
</div>
<div>{count}</div>
</>
)
}


하지만 의도한 대로 동작하지 않는다. 일정하게 1씩 증가되지 않고, 버튼이 활성화 될 때(n)마다 count 값이 n+1씩 증가된다. 이는 isActive가 변경 될 때마다 useEffect의 document.getElementById("add-button").addEventListener('mousedown', handleActionClick)
가 실행되고 이벤트리스너가 여러번 등록되어 발생하는 문제이다.
이 문제를 useEffect의 cleanup함수로 해결할 수 있다.
import { useEffect, useState } from "react"
export function Test() {
const [isActive, setIsActive] = useState(false);
const [count, setCount] = useState(0);
useEffect(() => {
if(!isActive) {
return
}
document.getElementById("add-button").addEventListener('mousedown', handleActionClick);
// cleanup : 이벤트리스너 제거
return () => document.getElementById("add-button").removeEventListener('mousedown', handleActionClick);
}, [isActive])
const handleActionClick = () => {
setCount(prev => prev + 1)
}
const handleChangeButtonActive = () => {
setIsActive(!isActive);
}
return (
<>
<div>
<button onClick={() => handleChangeButtonActive()}>
{isActive ?
<span>버튼 비활성화</span>
:
<span>버튼 활성화</span>
}
</button>
</div>
<div>
<button id="add-button" disabled={!isActive}>
더하기
</button>
</div>
<div>{count}</div>
</>
)
}

이제 버튼을 여러번 활성화시켜도 일정하게 1씩 증가하게 된다.
참고자료 😃
https://legacy.reactjs.org/docs/hooks-effect.html
https://react.dev/reference/react/useEffect#useeffect
'React' 카테고리의 다른 글
[React] 특정 영역의 외부 클릭 감지하기 (0) | 2024.03.10 |
---|