HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🐣
프론트엔드 데브코스 3기 교육생
/
🙂
동근팀
/
📚
학습 주제 목록
/
🏬
useEffect 무한 루프
🏬

useEffect 무한 루프

작성자
유지영
발표일
Dec 16, 2022
No
14

useEFFect 무한 루프가 발생하는 이유는?

주로 useEfffec에서 state 값을 변경할 때 일어난다.
import { useEffect, useState } from "react"; function App() { const [count, setCount] = useState(0); useEffect(() => { setCount(count + 1); }); return <div>{count}</div>; } export default App;
아래와 같은 에러를 띄우며 무한 루프가 발생하게 된다.
notion image
 
무한루프가 발생하는 이유는
  1. 첫 렌더링에서 count 값이 확인되고 useEffect 함수가 실행된다.
  1. useEffect 함수에서 setCount 메소드를 호출하고 count의 값을 업데이트한다.
  1. 바뀐 count 값으로 화면이 다시 렌더링 된다.
  1. 화면이 재렌더링 되면서 useEffect가 실행되고 setCount 를 호출하고…
 
이 과정이 반복되면서 무한루프에 빠지는 것이다.
 

무한루프 해결하기!

useEffect는 두 번째 인자로 종속성 배열을 받는다. useEffect는 리액트의 생명주기 함수의 역할을 하는데 두 번째 인자를 설정함으로써 componentDidUpdate 의 역할을 할 수 있다.
 
만약 빈배열을 갖는 경우 처음 렌더링 될 때만 실행되고,
특정 값이 있는 배열인 경우, 처음 렌더링 될 때와 그 배열의 값이 변경될 때 마다 실행된다.
 
하지만 이러한 종속성 배열이 없다면 useEffect는
  • 컴포넌트 생성 후 처음 렌더링 될 때,
  • 컴포넌트에 새로운 props가 전달되어 렌더링 될 때,
  • 컴포넌트의 state가 바뀌며 렌더링 될 때
작동하게 된다.
 
따라서 위에서의 무한루프 문제는 종속성 배열을 설정하여 해결할 수 있다.
import { useEffect, useState } from "react"; function App() { const [count, setCount] = useState(0); useEffect(() => { setCount(count + 1); }, []); return <div>{count}</div>; } export default App;
 
 

무한 루프가 발생하는 또 다른 이유

이 외에도 무한 루프가 발생하는 원인이 있는데 함수, 배열, 객체를 종속성 배열로 사용할 때이다.
useEffect는 얕은 비교를 하기 때문에 렌더링 될 때마다 참조 값이 변경되어 매번 호출되게 된다.
 
  1. 함수를 종속성으로 사용할 경우
function App() { const [count, setCount] = useState(0); function logResult() { return 2 + 2; } useEffect(() => { setCount((count) => count + 1); }, [logResult]); return ( <div className="App"> <p> value of count: {count} </p> </div>); }
 
  1. 함수는 컴포넌트가 리렌더링 될 때마다 새로 만들어진다.
  1. useEfffect가 실행되면서 count 값이 수정된다.
  1. 수정된 count 값으로 리렌더링된다.
  1. 함수가 새로 만들어진다.
…
 
이 문제를 해결하기 위해서 함수를 새로 만들지 않고 기억해서 재사용할 수 있는 useCallback 을 사용하면 된다.
function App() { ... const logResult = useCallback(() => { return 2 + 2; }, []); useEffect(()=> { setCount((count)=> count+1); },[logResult]); ... }
 
  1. 배열을 종속성으로 사용하는 경우
const [count, setCount] = useState(0); const myArray = ["one", "two", "three"]; useEffect(() => { setCount((count) => count + 1); }, [myArray]);
→ useEffect는 얕은 비교를 사용하므로 리렌더링 될 때마다 배열에 대한 참조가 변경되어 무한루프에 빠진다.
 
이 문제는 useRef 를 이용하여 해결 할 수 있다. useRef는 값이 바뀐다고 해서 컴포넌트가 리렌더링되지 않기 때문에 안정적으로 종속성 배열로 사용할 수 있다!
 
  1. 객체를 종속성으로 사용하는 경우
const [count, setCount] = useState(0); const person = { name: "Rue", age: 17 }; useEffect(() => { setCount((count) => count + 1); }, [person]); return ( <div className="App"> <p> Value of {count} </p> </div>);
→ 객체 역시 배열과 마찬가지로 얕은 비교로 인해 참조값이 변경되므로 무한 루프에 빠진다.
 
이 문제는 useMemo 를 사용해서 해결 할 수 있다. useMemo는 두 번째 파라미터로 넣는 종속성 배열의 내용이 바뀌면 첫 번째 파라미터로 등록한 함수를 호출해서 값을 연산한다.
const person = useMemo( () => ({ name: "Rue", age: 17 }), [] //디펜던시가 없으므로 값이 변경되지 않는다. 즉, useEffect에서 person객체를 디펜던시로 사용해도 참조값이 변경되지 않기 때문에 유지가 된다는 뜻이다. ); useEffect(() => { setCount((count) => count + 1); }, [person]);
이렇게 빈 배열를 설정할 경우 디펜던시가 없기 때문에 참조값이 변경되지않고 이전의 값을 재사용하기 때문에 참조값이 그대로 유지된다.