useEffect 란 ?
useEffect 란?
useEffect(callback, [dependencies])
Effect 란?
useEffect 는 왜 useEffect 라고 불리는걸까?
effect 란 무엇일까?
effect는 함수형 프로그래밍 용어인 "side effect" 를 의미한다.
side effect 가 뭔지 이해하기 위해 먼저 pure function 에 대해 이해 해 보자
대부분의 react component는 pure function 이 되려고 한다.
react component 를 함수라고 생각하는게 이상하겠지만 react component 는 함수다!
대부분의 react component는 pure function 이며 input을 받고 예측 가능한 JSX output을 만들어낸다.
export default function App() {
return <User name="John Doe" />
}
function User(props) {
return <h1>{props.name}</h1>; // John Doe
}
여기서 User Component는 name props 를 받고 항상 props와 같은 output을 낸다.
이런걸 pure function 이라고 한다!
pure function 은 예측 가능하고, 신뢰가 가고, 테스트하기 쉽다.
pure function 은 우리가 component의 side effect 를 필요로 할 때와 비교된다..
리액트에서 side effect 란?
side effect 는 예측할 수 없다. side effect 는 component 외부에서 발생하기 때문이다.
리액트 컴포넌트 외부에서 무언가 하기를 원할 때 side effect 를 수행한다.
side effect 를 수행하는것은 우리에게 예측 가능하지 않은 결과를 준다.
우리가 서버에게 실패 한 request data 를 줬다고 생각 해 보자.
서버는 500 상태코드를 반환 할거다.
일반적인 side effect 는 다음과 같다
- backend server에 API request 요청
- 브라우저 API와 상호작용 (document나 window를 직접적으로 쓸 때)
- 예측 할 수 없는 timing function 을 사용 할 때 (setTimeout 혹은 setInterval)
순수한 React 구성 요소에서 이러한 side effects 수행을 처리하기 위해 useEffect 가 존재한다.
즉 결과를 예측 할 수 없는 pure 하지 못한 상황 = side effect 라고 생각하면 되겠다.
이 결과를 예측 할 수 없는 side effect 를 제어하기 위해 사용하는 것이 useEffect 이다!
예시를 하나 보자.
function User({ name }) {
document.title = name;
// This is a side effect. Don't do this in the component body!
return <h1>{name}</h1>;
}
만약 side effect 를 component body 안에서 직접 수행하려 한다면 이 결과는 react 컴포넌트가 렌더링 될 때 수행된다.
side effect 는 rendering process 와 분리되어야한다.
만약 우리가 side effect 를 수행해야한다면, 이건 엄격하게 component 가 rendering 된 후 수행되어야한다.
요약하면, useEffect 는 component외부와 상호작용 할 수 있게 해 주는 도구이며
컴포넌트 내부의 렌더링과 퍼포먼스에는 영향을 미치지 않게 해준다.
useEffect 사용법
useEffect의 형태는 다음과 같다
// 1. import useEffect
import { useEffect } from 'react';
function MyComponent() {
// 2. call it above the returned JSX
// 3. pass two arguments to it: a function and an array
useEffect(() => {}, []);
// return ...
}
단계별로 보면,
- useEffect 를 import 한다.
- 리턴 될 JSX 위에서 호출한다.
- function 과 array. 두 arguments를 넘겨준다.
import { useEffect } from 'react';
function User({ name }) {
useEffect(() => {
document.title = name;
}, [name]);
return <h1>{name}</h1>;
}
useEffect에 넘겨질 function 은 callback function 이어야한다.
component가 render 된 후에 불려질 것이기 때문이다 ~
이 callback function 에서, 우리는 우리가 원하는 side effect 를 수행한다.
두번째 argument는 array이다. 이 array는 side effect가 의존하는 모든 값들의 집합니다.
위의 예시에서 document.title 이 외부에서 오는 name에 의해 변한다. 그래서 name 을 dependencies array 에 넣어 준 것이다.
이 array가 하는 것은 value가 render 될 때 변하는지 확인하고 지켜본다.
만약 value가 render시에 변했다면, useEffect 에게 준 callback function 이 다시 시행된다.
말이 된다 !!!
name이 바뀌면 우리의 document.title 도 바뀌어야하니까.. 다시 시행 되어야 함 !
useEffect 를 쓸 때 자주 하는 실수
만약 useEffect에게 dependencies array 를 제공하지 않고 callback 만 제공했다면.. 이 callback은 매 렌더때 마다 수행된다!
dependencies 가 제공되지 않을 때
import {useEffect} from 'react';
function MyComponent(){
useEffect(()=>{
// Runs after EVERY rendering
});
}
렌더링 순간 마다 callback 이 실행된다.
이건 state를 업데이트 하려고 할 때 문제가 될 수 있다.
만약 dependencies array를 제공하는 것을 잊었다면 , 그리고 state가 update될 때 local state 를 setting 되게 했다면
react 의 default 행동은 component를 rerender 하는 것이다.
useEffect 가 dependencies array 없이 매 렌더링 때 마다 수행된다면 우리는 무한 loop를 갖게 된다..
function MyComponent() {
const [data, setData] = useState([])
useEffect(() => {
fetchData().then(myData => setData(myData))
// Error! useEffect runs after every render without the dependencies array, causing infinite loop
});
}
first render가 되고 나서 , useEffect는 수행된다. state는 update되고 state가 update되면 re-render가 된다.
어..? re-render가 되고나면 또 useEffect를 수행하고 또 state가 update되고 또 re-render가 되고.....
무한대로 반복되게 되는구나!
이걸 무한 loop 라고 부르고 이건 우리 어플리케이션을 박살내게 된다 ㅜ_ㅜ
만약 useEffect 안에서 state를 update 한다면 빈 array를 dependencies로 제공하는 것을 잊지 말아야한다 !
dependencies로 빈 Array 를 제공하자
import { useEffect } from 'react';
function MyComponent(){
useEffect(()=>{
// Runs ONCE after initial rendering
}, []);
}
empty array 를 제공하면 컴포넌트가 맨 처음 렌더 됐을 때 effect function 을 수행하게 된다.
렌더링 이후 한번만 callback 이 실행된다.
이 경우는 일반적으로 data를 fetch 해 올 때 많이 사용된다.
function MyComponent() {
const [data, setData] = useState([])
useEffect(() => {
fetchData().then(myData => setData(myData))
// Correct! Runs once after render with empty array
}, []);
return <ul>{data.map(item => <li key={item}>{item}</li>)}</ul>
}
data를 한번만 fetch 하기 원한다면, [] 빈 array 를 넣어주자 !
props 혹은 state value들일 때
import { useEffect, useState } from 'react';
function MyComponent({prop}){
const [state, setState] = useState('');
useEffect(()=>{
// Runs ONCE after initial rendering
// and after every rendering ONLY IF 'prop' or 'state' changes
}, [prop, state]);
}
처음 렌더링 될 때 그리고 prop 혹은 state 가 변하는 순간마다 callback 이 실행된다.
특정 props나 state가 바뀌었을 때 수행하고싶은 함수가 있다면 dependencies에 그 props나 state를 넣어주자.
dependencie 로는 주로 빈 배열을 넣거나 prop 혹은 state를 넣는다.
useEffect에서 Cleanup function 이란?
때로 우리의 side effect 는 수행되지 않아야 할 때가 있다.
예를 들어 setInterval 함수를 사용해서 카운트다운 타이머를 가지고 있다면, interval 은 우리가 clearInterval 함수를 쓰지 않는 한 멈추지 않을거다.
다른 예시를 보자. webSockets 을 구독 할 때, 구독은 우리가 더이상 그들을 사용하고 싶지 않을 때 구독 해제가 필요하다.
그리고 이것은 cleanup 함수가 하는 일이다.
만약 우리가 setInterval을 사용해 state를 setting했다면, 컴포넌트가 unmount되고 더이상 사용되지 않을 때 side effect는 cleaned up 되지 않는다.
component upmount 시 state는 component와 함꼐 없어지지만 setInterval 함수는 계속 실행되게 된다.
function Timer() {
const [time, setTime] = useState(0);
useEffect(() => {
setInterval(() => setTime(1), 1000);
// counts up 1 every second
// we need to stop using setInterval when component unmounts
}, []);
}
위의 예시에서 컴포넌트가 destroy 되어 질 때, setInterval은 계속 수행되며 더 이상 존재하지 않는 time state를 변화시키려고 계속 시도한다. 이것이 Memory leak. 메모리 누수 라고 불리는 에러이다.
cleanup 함수를 쓰기위해, useEffect 안에서 함수를 리턴 해야한다.
function Timer() {
const [time, setTime] = useState(0);
useEffect(() => {
let interval = setInterval(() => setTime(1), 1000);
return () => {
// setInterval cleared when component unmounts
clearInterval(interval);
}
}, []);
}
cleanup 함수는 컴포넌트가 unmount 되어 질 때 호출된다.
컴포넌트가 unmount되는 일반적인 예제는 새로운 페이지로 가거나 새로운 route로 가거나 할 때 이다.
컴포넌트가 unmount 될 때 cleanup function 이 실행된다.
interval이 사라지고나면 우리는 더이상 에러가 발생하지 않는다 ~
side effect cleanup은 모든 케이스에 요구되지는 않는다.
컴포넌트가 unmount 될 때 반복되는 사이드 이펙트를 멈추고 싶을 때 사용하면 된다 !
참조
https://dmitripavlutin.com/react-useeffect-explanation/
https://www.freecodecamp.org/news/react-useeffect-absolute-beginners/
그럼 모두 즐코 ~ 🦄
'Front-end' 카테고리의 다른 글
[ antd ] antd table 의 pagination 한 페이지 열 갯수 설정하기 (0) | 2023.06.19 |
---|
댓글