ViewModel init 블록과 LauncedEffect

손현수·2024년 9월 9일

앱 내에서 userId, userIdx 값을 활용하여 통신하는 경우가 많아서 dataStore에 값을 저장하고 있다. 해당 값들을 사용하는 페이지의 경우에는 ViewModel의 init 블록에서 dataStore에 저장되어 있는 값들을 꺼내오고 서버 통신에 활용하려고 했는데 init 블록보다 LaunchedEffect의 호출이 더 빨라서 의도한 대로 동작하지 않았다.

ViewModel

@HiltViewModel
class HomeViewModel @Inject constructor(
    private val userRepository: UserRepository,
    private val deviceRepository: DeviceRepository,
    private val dataStore: LuxnineDataStore
) : BaseViewModel<HomePageState>(
    HomePageState()
) {
    init {
        viewModelScope.launch {
            combine(
                dataStore.userIdx,
                dataStore.userId
            ) { userIdx, userId ->
                Pair(userIdx ?: -1, userId ?: "")
            }.collect { (userIdx, userId) ->
                updateState(
                    uiState.value.copy(
                        userIdx = userIdx,
                        userId = userId
                    )
                )
            }
        }
    }
// 생략..
  • init 블록으로 dataStore에 저장되어 있는 userId, userIdx를 가져온다.

HomeScreen 컴포저블

    val viewModel: HomeViewModel = hiltViewModel()
    
    // 생략
    
    LaunchedEffect(key1 = Unit) {
        viewModel.getUserInfo()
        viewModel.getUserDevice()
    }
    
    // 생략
  • getUserInfo는 userId를 활용하여 서버에 데이터를 요청하는 함수이다.
  • getUserDevice는 userIdx를 활용하여 서버에 데이터를 요청하는 함수이다.

문제 해결

init보다 LaunchedEffect가 더 빨리 호출되고 있어서 이상한 값으로 서버에 데이터를 요청하고 있었고 이를 해결하기 위해 LaunchedEffect의 키값을 userId, userIdx로 설정하고 제대로 된 값이 아니라면 서버에 요청하지 않도록 변경하였다.

변경된 LaunchedEffect 코드

    LaunchedEffect(key1 = uiState.userId, key2 = uiState.userIdx) {
        if (uiState.userId.isNotEmpty() && uiState.userIdx != -1L) {
            viewModel.getUserInfo()
            viewModel.getUserDevice()
        }
    }
  • 두개의 값이 하나라도 기본값이라면 요청을 보내지 못하도록 수정하였다.
profile
안녕하세요.

2개의 댓글

comment-user-thumbnail
2024년 9월 9일

잘 보고 갑니다~^^..좋은.,개발자가..되실듯..아자아자

1개의 답글