🧑🏻💻 useEffect
useEffect
는 컴포넌트를 외부 시스템과 동기화할 수 있는 React 훅
🍪 useEffect 문법
useEffect(setup, dependencies?)
useEffect
는 컴포넌트의 최상위 레벨 또는 자체 훅에서만 호출 가능하다. (React 훅)
🧑🏻💻 참고하기
🍪 주의 사항
- Strict 모드가 켜져 있으면 React는 첫 번째 실제 셋업 전에 “개발 전용의 셋업+클린업 사이클”을 한 번 더 실행한다.
- Effect가 상호작용으로 인한 것이 아니라면, React는 브라우저가 Effect를 실행하기 전에 업데이트된 화면을 먼저 그리도록 한다. 그러나, 상호작용으로 인해 Effect가 발생하더라도, 브라우저가 화면을 다시 칠하지 못하도록 차단해야 하는 경우에는
useLayoutEffect
로 대체하는 것이 좋다.
- Effects는 클라이언트에서만 실행된다. 서버 렌더링 중에는 실행되지 않는다.
- 컴포넌트를 외부 시스템에 연결하려면 컴포넌트의 최상위 레벨에서
useEffect
를 호출해야 한다.
🍪 실행 순서
import { useEffect } from 'react';
import { createConnection } from './chat.js';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
}
- 컴포넌트가 페이지에 추가될 때 (마운트) 마다 셋업 코드를 실행한다.
- 의존성이 변경된 컴포넌트를 다시 렌더링할 때마다
- 먼저 이전 props와 state로 클린업 코드를 실행한다.
- 그런 다음 새 props와 state로 셋업 코드를 실행한다.
- 컴포넌트가 페이지에서 제거되면 (마운트 해제) 마지막으로 한 번 클린업 코드를 실행한다.
🍪 반응형 의존성 지정
- 반응형 값에는 props와 컴포넌트 내부에서 직접 선언된 모든 변수, 함수가 포함된다.
- Effect의 의존성을 “선택”할 수 없고 Effect의 코드에서 사용되는 모든 반응형 값은 의존성으로 선언해야 하고 React 용으로 구성된 린터가 이를 체크한다.
- 전달 예시
- 의존성 배열 전달하는 경우 : 마운트될 때 실행, 변경된 의존성으로 다시 렌더링한 후 실행, 언마운트할 때 클린업 실행
- 빈 의존성 배열 전달하는 경우 : 마운트될 때 실행, 언마운트할 때 클린업 실행
- 아예 의존성 배열을 전달하지 않는 경우 : 컴포넌트의 모든 렌더링(및 리렌더링) 후마다 매번 Effect가 실행
- 렌더링 중에 생성된 객체나 함수는 의존성으로 사용하지 않고 대신 Effect 내에 생성하여 불필요한 의존성을 제거한다.
🧑🏻💻 활용 및 생각할 거리
🍪 자동 가비지 컬렉션에 의존하는 대신 명시적인 클린업 함수를 사용하는 것이 좋은 이유는?
- 브라우저의 JavaScript 엔진에서는 더 이상 사용되지 않는 객체 및 리소스를 자동으로 수거하는 가비지 컬렉션이 있다. 메모리 해제를 담당하지만 그 동작을 제어할 수 없어서 명시적인 클린업 함수를 사용해 메모리 관리를 예측 가능하게 제어하는 것이 좋다. 이는 또한 코드의 가독성과 유지 보수의 효율을 올리고 메모리 누수 문제를 방지한다.
🍪 Effect에서 데이터 페칭하는 것을 비추천하는 이유는?
- Effects에서 직접 데이터를 페칭하는 작업을 반복적으로 작성하면 나중에 캐싱 및 서버 렌더링과 같은 최적화를 추가하기가 어려워진다. 또한 코드 중복이 발생하고 유지 보수가 어려워질 수 있다. 직접 만들거나 커뮤니티에서 유지 관리하는 커스텀 훅을 사용하는 것이 더 효율적이고framework를 사용하는 경우, 프레임워크 빌트인 데이터 페칭 메커니즘을 사용하는 것이 더 효율적이다.
🍪 Effect의 이전 state를 기반으로 state를 업데이트하려는 경우 문제 해결 방법
import { useState, useEffect } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setCount(c => c + 1);
}, 1000);
return () => clearInterval(intervalId);
}, []);
return <h1>{count}</h1>;
}
- count + 1대신 c => c + 1을 전달하면 Effect는 더 이상 count에 의존할 필요가 없고 count가 변경될 때마다 interval을 다시 클린업하고 셋업하지 않는다.
🍪 서버와 클라이언트에 서로 다른 콘텐츠 표시하는 방법
참고 https://react-ko.dev/reference/react/useEffect