노트

Effect가 필요 없는 경우

You Might Not Need an Effect

프런트엔드#react · 연결된 개념 7개

쉽게 말하면

Effect는 외부 시스템과 맞출 때 쓰는 비상구예요. props에서 바로 계산되는 값까지 Effect로 따로 맞추면 렌더가 한 번 더 돌고 흐름만 꼬이니, 렌더 중에 그냥 계산하면 돼요.

비유가 깨지는 곳 비상구를 아예 쓰지 말라는 건 아니에요. 화면에 보였기 때문에 외부와 맞춰야 하면 Effect, 사용자가 뭔가 했기 때문이면 이벤트 핸들러예요. prop이 바뀔 때 state 초기화는 key로 해요.

Effect는 외부 시스템과 동기화할 때 쓰는 탈출구(Escape Hatch)다. 렌더 중에 계산할 수 있는 값이나 사용자 이벤트 처리에 Effect를 쓰면 렌더가 한 번 더 일어나고 흐름이 꼬인다. React 공식 문서가 이런 경우를 따로 정리해 두었다.

  • props·state에서 계산되는 값은 그냥 렌더 중에 계산한다. 별도 state와 Effect로 동기화하지 않는다. 비싼 계산이면 useMemo로 캐시한다(정말 비싼지는 console.time으로 잰다)
  • prop이 바뀔 때 state 전체를 초기화하려면 컴포넌트에 다른 key를 준다(재조정(Reconciliation))
  • 일부 state만 조정하려면 이전 값을 state에 저장해 두고 렌더 중에 비교한다
const [prevCount, setPrevCount] = useState(count)
if (prevCount !== count) {           // 렌더 중 자기 state 갱신
  setPrevCount(count)
  setTrend(count > prevCount ? 'up' : 'down')
}

React는 반환된 JSX(JavaScript XML)를 버리고 바로 다시 렌더한다. 조건이 있어 한 번에 수렴하고, 지금 렌더 중인 컴포넌트 자신의 state만 고치기 때문에 허용된다. 부모나 다른 컴포넌트의 state를 고치면 안 된다. React 19의 새 기능이 아니라 오래전부터 가능했던 동작이고, Effect 남용을 줄이자는 흐름에서 다시 주목받았다

  • 사용자 이벤트 때문에 일어나는 일은 이벤트 핸들러에 둔다. "이 코드가 왜 실행돼야 하나?"를 묻는다. 화면에 보였기 때문이면 Effect, 사용자가 무언가 했기 때문이면 핸들러다
  • Effect끼리 state를 연쇄로 갱신하면 단계마다 렌더가 반복된다. 한 이벤트 안에서 한 번에 계산한다
  • 여러 컴포넌트의 state를 맞추려 한다면 state를 위로 올린다(Lifting State Up)(React 상태 갱신)
  • Effect로 데이터를 가져온다면 정리 함수로 경쟁 상태(Race Condition)를 막는다. 보통은 TanStack Query나 서버 컴포넌트가 더 낫다

배경은 부수 효과와 Effect, 최신 값을 읽되 재실행은 막는 도구는 useEffectEvent.

출처: React - You Might Not Need an Effect

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • React의 규칙과 렌더 순수성

    Rules of React는 React가 올바르게 동작하고 최적화하기 위해 코드가 지켜야 하는 규칙으로, 공식 문서가 세 가지로 정리한다. 핵심은 렌더가 순수한 계산이어야 한다는 것이다.

  • 서버 렌더에서 훅이 하는 일

    서버 렌더(Server-Side Rendering, SSR)에서도 컴포넌트 함수는 실제로 호출되고, 그 안의 훅도 호출은 된다. 다만 서버에는 커밋(DOM 반영)이 없어서, 렌더 중 동기적으로 값을 계산하는 훅만 일하고 커밋 뒤에 도는 훅은 아무것도 하지 않는다. "이 훅은 클라이언트에서만 동작한다"는 말은 대개 "Effect 안의 일은 클라이언트에서만 일어난다"는 뜻이다.

  • useEffect와 useLayoutEffect

    useLayoutEffect는 useEffect와 같은 일을 하지만, 브라우저가 화면을 그리기(Paint) 전에 동기적으로 실행된다. useEffect는 그린 뒤에 실행된다.

  • 내부 가변성과 메모이제이션

    내부 가변성(Interior Mutability)은 객체나 함수의 참조는 그대로인데 안에 숨은 상태가 바뀌는 성질이다. React의 메모이제이션은 "입력이 다른 참조인가"만 보기 때문에, 참조가 같으면 내용이 바뀌어도 바뀌지 않았다고 판단한다. React 공식 문서는 이를 "겉모습은 같은데 몰래 내용물을 바꾸는 상자"에 비유한다.

  • memo·useMemo·useCallback

    React의 메모이제이션(Memoization) 도구 셋은 모두 "입력이 같으면 이전 결과를 재사용"하는 캐시지만 대상이 다르다. useMemo는 계산한 값, useCallback은 함수, React.memo는 컴포넌트의 렌더 결과를 캐시한다.

보기 옵션