본문 바로가기

React

React에서 발생하는 "Can't perform a state update on an unmounted component" 오류의 원인과 해결 방법

반응형

React 개발 시 자주 발생하는 "Can't perform a React state update on an unmounted component" 오류의 원인과 해결 방법을 심층적으로 분석합니다. 비동기 작업 관리부터 커스텀 Hooks 활용까지, 오류를 효과적으로 해결하는 다양한 전략을 소개합니다.

 

오류의 배경과 중요성

React는 컴포넌트 기반 아키텍처를 통해 복잡한 사용자 인터페이스를 효율적으로 관리할 수 있게 해줍니다. 하지만, 개발 과정에서 다양한 오류가 발생할 수 있으며, 그 중 하나가 바로 "Can't perform a React state update on an unmounted component" 오류입니다. 이 오류는 개발자에게 혼란을 줄 수 있으며, 애플리케이션의 안정성과 성능에 영향을 미칠 수 있습니다.

 

"Can't perform a React state update on an unmounted component" 오류란?

오류 메시지 "Can't perform a React state update on an unmounted component"는 React 컴포넌트가 언마운트된 후에 상태(state)를 업데이트하려 할 때 발생합니다. 이는 컴포넌트가 더 이상 DOM에 존재하지 않는데도 불구하고 상태를 변경하려는 시도로 인해 발생하며, 메모리 누수나 예기치 않은 동작을 유발할 수 있습니다.

 

오류의 주요 원인 분석

비동기 작업과 컴포넌트 언마운트

비동기 작업은 일반적으로 컴포넌트가 마운트된 후에 실행되며, 작업 완료 시 상태를 업데이트합니다. 하지만, 작업이 완료되기 전에 컴포넌트가 언마운트되면, 상태 업데이트 시도가 오류를 발생시킵니다.

잘못된 상태 업데이트 로직

상태 업데이트 로직이 컴포넌트의 마운트 상태를 고려하지 않고 무조건 실행될 경우, 언마운트된 컴포넌트에 상태 업데이트를 시도하게 됩니다. 이는 주로 비동기 함수 내에서 발생합니다.

외부 라이브러리 사용 시 주의점

외부 라이브러리를 사용할 때, 해당 라이브러리가 컴포넌트의 생명주기를 제대로 관리하지 않으면 언마운트된 컴포넌트에 접근하여 상태를 업데이트하려 시도할 수 있습니다.

 

오류 해결 방법

컴포넌트 언마운트 시 정리 함수 사용하기

React의 useEffect Hook은 컴포넌트가 언마운트될 때 실행되는 정리(clean-up) 함수를 제공합니다. 이 정리 함수를 사용하여 비동기 작업을 취소하거나, 상태 업데이트를 막을 수 있습니다.

import React, { useState, useEffect } from 'react';

function DataFetcher({ url }) {
	const [data, setData] = useState(null);

	useEffect(() => {
		let isMounted = true;

		fetch(url)
			.then(response => response.json())
			.then(result => {
				if (isMounted) {
					setData(result);
				}
			})
			.catch(error => {
				if (isMounted) {
					console.error('데이터 패칭 오류:', error);
				}
			});

		return () => {
			isMounted = false;
		};
	}, [url]);
    
	return <div>{data ? data.title : '로딩 중...'}</div>;
}

export default DataFetcher;

 

isMounted 플래그를 이용한 상태 업데이트 제어

isMounted 플래그를 사용하여 컴포넌트가 마운트된 상태에서만 상태 업데이트를 수행하도록 제어할 수 있습니다. 이는 위의 예제에서도 사용된 방법으로, 컴포넌트 언마운트 시 플래그를 false로 설정하여 상태 업데이트를 방지합니다.

AbortController를 활용한 비동기 요청 취소

AbortController를 사용하면 비동기 요청을 취소할 수 있어, 컴포넌트가 언마운트될 때 요청을 중단하여 상태 업데이트 시도를 방지할 수 있습니다.

import React, { useState, useEffect } from 'react';

function DataFetcher({ url }) {
	const [data, setData] = useState(null);
    
	useEffect(() => {
		const controller = new AbortController();
		const signal = controller.signal;
        
		fetch(url, { signal })
			.then(response => response.json())
			.then(result => setData(result))
			.catch(error => {
				if (error.name !== 'AbortError') {
					console.error('데이터 패칭 오류:', error);
				}
		});

		return () => {
			controller.abort();
		};
	}, [url]);
    
	return <div>{data ? data.title : '로딩 중...'}</div>;
}

export default DataFetcher;

 

커스텀 Hooks를 통한 재사용 가능한 해결책

커스텀 Hooks를 사용하여 상태 업데이트 오류를 예방하는 로직을 재사용 가능하게 만들 수 있습니다. 예를 들어, useSafeState Hook을 만들어 컴포넌트가 언마운트된 후에도 상태 업데이트를 시도하지 않도록 할 수 있습니다.

import { useState, useEffect, useRef } from 'react';

function useSafeState(initialState) {
	const [state, setState] = useState(initialState);
	const isMounted = useRef(true);
    
	useEffect(() => {
		return () => {
			isMounted.current = false;
		};
	}, []);
    
	const safeSetState = (newState) => {
		if (isMounted.current) {
			setState(newState);
		}
	};
    
	return [state, safeSetState];
}

export default useSafeState;
import React, { useEffect } from 'react';
import useSafeState from './useSafeState';

function DataFetcher({ url }) {
	const [data, setData] = useSafeState(null);

	useEffect(() => {
		fetch(url)
			.then(response => response.json())
			.then(result => setData(result))
			.catch(error => {
				console.error('데이터 패칭 오류:', error);
			});
    }, [url]);
    
	return <div>{data ? data.title : '로딩 중...'}</div>;
}

export default DataFetcher;

 

마무리하며

이번 글에서는 "Can't perform a React state update on an unmounted component" 오류의 원인과 다양한 해결 방법에 대해 심층적으로 살펴보았습니다. 비동기 작업 관리부터 AbortController 활용, 커스텀 Hooks 작성까지, 여러 전략을 통해 이 오류를 효과적으로 해결할 수 있습니다. React 애플리케이션의 안정성과 성능을 높이는데 이러한 방법들이 도움이 되길 바랍니다.

반응형