본문 바로가기
개발 기록/front - react

React의 UseEffect는 왜 두 번씩 실행되어 빡치게 만드는가

by jeong11 2024. 11. 16.
반응형

React 게시판을 만들다가 조회수 구현을 하는데 게시글을 클릭할 때 마다 조회수가 두번씩 올랐다 
 

console.log... console.log...

 왜 이러는지 이유를 찾아보겠다

 

React에서 useEffect 실행 방식 

 useEffect : 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook이다 
1) useEffect가 처음 렌더링될 때만 실행하고 싶다 
= 마운트 될 때만 실행된다 

useEffect(() => {
	//마운트 시 API 호출
    axios.get('https://api.example.com/posts')
    	.then(response => setData(response.data))
        .catch(error => console.error('데이터 로드 실패:', error));
}, []);	// 빈 배열로 설정해 마운트 시 한번만 실행

 
useEffect의 두번째 매개변수로 전달되는 빈 배열 []은 의존성 배열이다
의존성 배열이 비어있으면 useEffect는 컴포넌트가 처음 마운트될 때만 실행되고 이후에는 실행되지 않는다 
 
2) 특정 값이 업데이트 될 때만 호출하고 싶다 
useEffect를 사용할 때 특정 값이 변경이 될 때만 호출하고 싶다면 의존성 배열에 해당 값을 포함하면 된다 

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

const UpdateEffectExample = () => {
	const [count, setCount] = useState(0);
    const [text, setText] = useState('');
    
    //count 값이 변경될 때만 실행
    useEffect(() => {
    	console.log('count가 변경되었습니다: ${count}');
    }, [count]);  //count를 의존성 배열에 추가
    
    return (
    	<div>
        	<p>Count: {count}</p>
            <button onClick{() => setCount(count +1)}> Increment Count</button>
            
            <p>
            	Text: <input value={text} onchange={(e) => setText(e.target.value)} />
            </p>
        </div>
    );  
};

export default UpdateEffectExample;

useEffect는 count 값이 변경될 때만 실행된다
text 값이 변경되어도 useEffect는 실행되지 않는다(의존성 배열에 포함되지 않았기 때문)
count가 업데이트될 때마다 콘솔에 로그가 출력된다 
 
3) 여러 값이 업데이트될 때 실행

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

const MultiDependencyExample = () => {
	const [name, setName] = useState('');
    const [age, setAge] = useState(0);
    
    //name 또는 age가 변경될 때 실행
    useEffect(() => {
    	console.log('Name 또는 Age가 변경되었습니다. Name: ${Name}', Age:${age}');
        }, [name, age]); //name, age를 의존성 배열에 추가
    
    return (
    <div>
      <p>
        Name: <input value={name} onChange={(e) => setName(e.target.value)} />
      </p>
      <p>
        Age: <input type="number" value={age} onChange={(e) => setAge(e.target.value)} />
      </p>
    </div>     
    };
};

export default MultiDependencyExample;

name 또는 age가 변경되면 useEffect 내부 코드가 실행된다
의존성 배열에 여러 값을 포함하면 해당 값들 중 하나라도 변경될 때 useEffect가 실행된다
 
 
4) 정리 : 
useEffect는 기본적으로 렌더링되고 난 직후마다 실행되며, 두번째 파라미터 배열에 무엇을 넣느냐에 따라서 실행되는 조건이 달라진다 
 
 
 
해결 방법
허무함

index.js 주석으로 해결된 문제

프로젝트의 index.js에서 해결할 수 있었다
<App />을 감싸고 있는 <React.StrictMode>태그를 주석 처리하니 간단히 해결되었다 
 그게 뭐냐면,,,
 

React의 StrictMode

리액트에서 제공하는 검사도구. 
개발모드일 때 디버그를 통해, 이 태그로 감싸져있는 App 컴포넌트를 검사한다 
안전하지 않은 생명 주기를 가진 컴포넌트, 권장되지 않은 부분, 배포 후 문제가 될 수 있는 부분들까지 미리 확인함

 
1) 'react-node-app'을 생성할 때 다음과 같이 생성했었는데 

npx create-react-app react-node-app

create-react-app으로 앱을 만들면 해당 태그가 기본적으로 생성된다
 
2) useEffect를 두 번 실행하는 이유
① 부작용 감지 : 
리액트의 useEffect는 컴포넌트가 마운트될 때 실행된다
개발 중에 <React.StrictMode>는 마운트 과정을 두 번 실행해 useEffect 내부에 정의된 부작용 코드가 안전하게 작동하는지 확인한다 
 
② 클린업 테스트
useEffect에서 반환된 클린업 함수가 제대로 작동하는지 확인하기 위해 useEffect 실행 - 클린업 - 재실행 과정을 반복한다
 
③ 개발 중 실수 방지
개발자가 상태 업데이트나 부작용 코드를 잘못 작성하여 의도치 않은 동작을 유발하는 경우를 방지하기 위해 실행된다
 
<참고 : 리액트 공식 문서>
https://ko.legacy.reactjs.org/docs/strict-mode.html

Strict 모드 – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

 

반응형