내 머리 속의 useEffect

Lee Sang Hyuk·2022년 11월 24일
1

React

목록 보기
1/4
post-thumbnail

useEffect는 무엇인가

👉 “Side Effect를 수행할 수 있는 함수”

렌더링 이후 비동기로 처리되어야 하는 부수적인 효과(Side Effect)를 처리하기 위해서는 useEffect를 사용한다. 비동기 처리가 필요한 요소는 대표적으로 외부 API를 호출하여 데이터를 처리해야 할 경우이다. 첫 렌더링 이후 데이터를 비동기로 가져오는 것이 좋은 이유는 응답이 늦거나 없을 경우에 대한 영향을 최소화 시킬 수 있어 사용자 경험 측면에 유리하다는 내용이 있었다.

꼭, 외부 API가 대상이 아니여도 외부 라이브러리, 이벤트 리스너 등을 활용하게 될 경우 useEffect로 특정 효과를 적절한 시기에 발생되도록 할 수 있다.

useLayoutEffect랑 비교하면

useEffect는 render 및 paint 과정을 거친 후 비동기적으로 실행이 된다. 만약, DOM에 영향을 주는 코드가 useEffect 내부에 있을 경우, 사용자 측면에서는 화면의 깜빡임(Blinking) 현상을 보게 된다.

useLayoutEffect는 render 과정을 거친 후 paint 과정 전에 동기적으로 실행이 된다. DOM에 영향을 주는 코드가 useLayoutEffect 내부에 있더라도 사용자는 깜빡임을 보지 못한다. 로직이 복잡하면 사용자가 레이아웃을 보는데까지 시간이 오래 걸린다는 단점이 있어, 기본적으로 useEffect 만으로 해결한다고 권장한다.

👉 useLayoutEffect를 효과적으로 사용할 수 있는 경우는 “**첫 painting 시 다르게 렌더링**”이 필요할 때의 경우이다.
const App = () => {
	const [value, setValue] = useState(0);

	useLayoutEffect(() => {
		if(value === 0) {
			setValue(Math.random() * 100);
		}
	}, [value]);

	return (
		<button onClick={() => setValue(0)}>
			value: {value}
		</button>
	);
}

해당된 상황 같은 경우 useLayoutEffect 대신 useEffect를 사용할 경우 첫 painting 과정을 거친 후 0이 보여지고 value === 0 의 조건에 의해 re-rendering이 되어 화면이 깜빡거려지는 현상이 생긴다. 그래서, useLayoutEffect도 적절한 상황 때 사용하면 사용자한테 불필요한 깜빡임을 보여주는 것에 방지할 수 있다.

의존성에 따라 다르게 실행되나요

useEffect도 원하는 상황별로 발생되었을 때 실행 시킬 수 있는 방법이 있다. 기본 형태는 useEffect(function, deps)로 이루어져 있으며 deps의 값에 따라 원하는 상황에 실행할 수 있다.

// 의존성이 아무 값도 없을 경우

useEffect(() => {
	console.log("show this log when it's rendering");
});

// 의존성이 빈 배열일 경우

useEffect(() => {
	console.log("show this log when it's mounted");
}, []);

// 의존성이 배열 형태이며 어떠한 값이 있을 경우

useEffect(() => {
	console.log(value);
	console.log(`show this log when the ${value} has change`);
}, [value]);

만약, useEffect 내에 컴포넌트의 props 또는 state가 사용될 경우, 의존성에 할당해 줘야 최신 상태의 값으로 처리할 수 있다. ESLint 중에서 ‘react-hooks/exhaustive-deps’를 사용할 경우, 놓친 의존성 값들을 경고 형태로 알려주기도 한다.

const App = () => {
    const [value1, setValue1] = useState(0);
    const [value2, setValue2] = useState(0);

		// 배열의 값이 두 개 이상으로 의존할 경우
    useEffect(() => {
        console.log(value1);
        console.log(value2);
				setValue1(value => value + 1);
				setValue2(value => value + 1);
        console.log('render by value1 or value2');
    }, [value1, value2]);

    return (
        <p>value1 : {value1}, value2: {value2}</p>
    )
}

또한, 배열의 값이 두 개 이상이면 모두 값이 변경될 때 실행되는 것이 아니라 한 개의 값이라도 변경될 경우 useEffect가 실행하게 된다. 위에 있는 경우는 정상적으로 동작하지 않는 나쁜 코드의 예시이다. 적절하게 동작하도록 바꿀 수 있다면 아래와 방법이 있다. 꼭 아래 방법 외에, 커스텀 훅(Custom Hook)을 사용하여 유지보수 및 코드 읽기에 용이하다.

// 의존하는 값들을 분리

useEffect(() => {
    console.log(value1);
		setValue1(value => value + 1);
    console.log('render by value1');
}, [value1]);

useEffect(() => {
    console.log(value2);
		setValue2(value => value + 1);
    console.log('render by value2');
}, [value2]);


React.js 공식 문서에 useEffect를 여러 개 사용하여 작업 분리하는 내용

Clean-up도 중요

위에 useEffect는 Side Effect를 수행한다고 했으며, 렌더링이 발생 시 메모리 누수(Memory Leak)가 일어날 수 있다. 이이 때, clean-up 함수를 사용하게 되면 렌더링이 될 때, 이전에 남은 함수가 실행되어 메모리 누수가 일어나는 일을 막을 수 있다.

clean-up 같은 경우, 모든 effect에 적용할 필요는 없다. 중요한 건 unmount될 때 반복되는 Side Effect를 중지할 필요 있거나 다음 effect를 위한 준비가 필요할 때 적용하면 된다.

👉 props/state 업데이트 → 컴포넌트 re-rendering → 이전 effect의 clean-up → 새로운 effect 실행
// setInterval을 활용한 예시

const Timer = () => {
	const [time, setTime] = useState(0);

	useEffect(() => {
		const interval = setInterval(() => setTime(1), 1000);

		return () => {
			clearInterval(interval);
		}
	}, []);
}

두 번 실행되는 경우

useEffect(() ⇒ {}, []) 를 사용했음에도 불구하고 두 번 실행되는 경우가 있다.

// src/index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>  // <- 이거이거!
    <App />
  </React.StrictMode>   
);

Strict Mode 는 개발 모드일 때 디버그를 하며 해당 태그로 감싸져 있는 부분의 자손까지 검사를 한다. 보통 안전하기 않는 LifeCycle를 가진 컴포넌트, React에서 권장하지 않는 부분, 배포 후 문제가 될 요소들을 미리 잡는 모드이다. React를 생성하면 Default로 설정된 것이기 때문에 특별하지 않는 이상 지워서 개발한다고 한다.

profile
개발자가 될 수 있을까?

0개의 댓글