본문 바로가기
카테고리 없음

Jetpack Compose에서 SideEffect란?

by h4r3 2025. 2. 17.
반응형

 

Jetpack Compose에서 SideEffect는 컴포저블이 리컴포지션될 때마다 실행되는 코드 블록을 정의하는 데 사용됩니다. 이는 주로 Compose의 상태 관리와 관계없는 작업(예: 로그 출력, 외부 상태 업데이트 등)을 수행할 때 유용합니다.

 


 

📌 SideEffect의 동작 방식

  • SideEffect는 컴포지션 단계에서 실행됩니다.
  • 컴포저블이 리컴포지션될 때마다 호출됩니다.
  • Compose 내부에서 상태를 변경하지 않는 부수 효과(Side Effect)를 안전하게 실행할 수 있도록 도와줍니다.

 


 

🔍 SideEffect를 사용하는 이유

  1. 컴포저블의 리컴포지션 확인
    • SideEffect를 활용하여 특정 컴포저블이 얼마나 자주 리컴포지션되는지 확인할 수 있습니다.
  2. Compose 상태와 관계없는 외부 상태 업데이트
    • 예를 들어, 네트워크 호출을 트리거하거나, 로그를 남기거나, 특정 이벤트를 추적할 때 사용할 수 있습니다.
  3. Compose 내부에서 UI 상태를 직접 변경하지 않고 외부 이벤트를 처리
    • SideEffect는 UI 상태를 변경하지 않고 외부 시스템과의 연계를 쉽게 해줍니다.

 


 

🛠 SideEffect 사용 예제

1️⃣ 리컴포지션 횟수 추적하기

@Composable
fun MyComposable() {
    val recompositionCount = remember { mutableStateOf(0) }

    SideEffect {
        recompositionCount.value++
        Log.d("Recomposition", "MyComposable recomposed ${recompositionCount.value} times")
    }

    Text("리컴포지션 횟수: ${recompositionCount.value}")
}

📌 설명:

  • SideEffect 블록 안에서 recompositionCount.value++을 실행하여 컴포저블이 리컴포지션될 때마다 카운트를 증가시킵니다.
  • Log.d(...)를 사용하여 리컴포지션 횟수를 확인할 수 있습니다.
  • 이 코드 실행 시, 상태가 변경될 때마다 로그가 출력됩니다.

2️⃣ 외부 API 호출 (로깅 시스템과 연동)

@Composable
fun MyComposable(userName: String) {
    SideEffect {
        Log.d("UserTracking", "User viewed: $userName")
    }

    Text(text = "Hello, $userName!")
}

📌 설명:

  • 이 예제에서는 SideEffect를 사용하여 컴포저블이 리컴포지션될 때마다 로그를 남김으로써 사용자의 화면 방문을 추적할 수 있습니다.
  • userName이 변경될 때마다 SideEffect 내부의 코드가 실행됩니다.

 


 

3️⃣ 외부 객체 업데이트 (예: ViewModel 상태 변경)

@Composable
fun MyComposable(viewModel: MyViewModel) {
    val counter = remember { mutableStateOf(0) }

    Button(onClick = { counter.value++ }) {
        Text("Click me: ${counter.value}")
    }

    SideEffect {
        viewModel.updateCounter(counter.value)
    }
}

📌 설명:

  • SideEffect를 이용해 뷰모델(ViewModel)의 상태를 업데이트합니다.
  • 버튼 클릭 시 counter.value가 증가하며, 그 값이 SideEffect 내부에서 viewModel.updateCounter()로 전달됩니다.
  • 이 방법을 사용하면 Compose의 상태 변화가 외부 객체에 올바르게 반영됨을 보장할 수 있습니다.

 


 

🚨 SideEffect 사용 시 주의할 점

  1. Compose의 상태를 변경하면 안 됨
    • SideEffect 내부에서는 Compose 상태를 직접 변경하면 안 됩니다.
    • Compose 상태는 remember, mutableStateOf 등을 활용해야 하며, SideEffect는 외부 시스템과의 연동을 위한 역할을 수행해야 합니다.
  2. 리컴포지션이 잦다면 불필요한 SideEffect 호출을 피해야 함
    • SideEffect는 리컴포지션마다 실행되므로, 빈번한 리컴포지션이 발생할 경우 불필요한 API 호출이나 이벤트 발생이 일어날 수 있습니다.
    • 이 문제를 해결하려면 불필요한 리컴포지션을 최소화하는 최적화 작업이 필요합니다.
    • 예를 들어, remember나 derivedStateOf를 활용하여 리컴포지션을 줄일 수 있습니다.

 


 

🎯 SideEffect vs LaunchedEffect 차이점

기능 SideEffect LaunchedEffect

실행 시점 매 리컴포지션마다 실행 처음 Composition이 생성될 때 실행
코루틴 사용 여부 ❌ 불가능 (단순 블록 실행) ✅ 가능 (Suspend 함수 실행 가능)
주 사용 목적 상태 변경 없이 외부에 영향 주기 (로그, 이벤트 등) 비동기 작업 실행 (네트워크, 데이터 로딩 등)

예제 코드 비교

✅ SideEffect: 매 리컴포지션마다 실행됨

@Composable
fun MyComposable() {
    SideEffect {
        Log.d("Debug", "Recomposition 발생!")
    }
}

✅ LaunchedEffect: 처음 1회만 실행됨

@Composable
fun MyComposable() {
    LaunchedEffect(Unit) {
        delay(1000)
        Log.d("Debug", "1초 후 실행됨")
    }
}

📌 정리:

  • SideEffect는 리컴포지션이 발생할 때마다 실행되므로, 외부 상태를 업데이트하는 용도로 적합합니다.
  • 비동기 작업을 실행해야 한다면 LaunchedEffect를 사용하는 것이 적절합니다.

 


 

🎯 결론

  • SideEffect는 컴포저블이 리컴포지션될 때마다 실행되는 코드 블록을 정의하는 데 사용됩니다.
  • 외부 API 호출, 로깅, 뷰모델 업데이트Compose 내부 상태와 관계없는 작업을 수행할 때 적합합니다.
  • LaunchedEffect와는 달리 코루틴을 사용할 수 없으며, 리컴포지션마다 실행되므로 필요하지 않은 경우 사용을 피해야 합니다.
  • 불필요한 리컴포지션을 방지하는 것이 성능 최적화의 핵심입니다.

 


📝 추가로 보면 좋은 문서

반응형