State Hoisting & ViewModel

💡Hoisting

변수의 선언과 초기화를 분리한 후 선언 부분만 코드의 최상단으로 옮기는 행위

  • 컴포저블 내부에서 관리하던 상태를 상단으로 호이스팅 하는 것
  • 상태 관련된 변수를 매개변수로 바꿈으로써 이루어짐
    • value: T ⇒ 컴포저블이 다룰 상태 값
    • onValueChange: (T) → Unit ⇒ 상태의 값을 변경하도록 요청하는 이벤트이며, T는 컴포저블에 제안할 새로운 값
  • 상태를 호이스팅함으로써 여러 컴포저블과 상태를 공유할 수 있으며 상태를 어디에나 저장할 수 있음
  • 상태는 내려가고 이벤트는 올라가는 단방향 데이터 흐름 패턴이 사용 됨

 

 

💡ViewModel

  • 크기가 비교적 큰 데이터는 UI 코드로 저장하기에 부담이 있으므로 따로 분리하여 데이터를 보관하고 UI를 변경하기 위해 ViewModel 사용
  • 액티비티와 같은 라이프사이클을 가지기 때문에 remember를 신경 쓰지 않아도 됨
  • ex)
class MainActivity : ComponentActivity() {
	private val viewModel by viewModels<MainViewModel>()  // viewModel 불러오기

	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
	
		setContent {
			Column(
				modifier =Modifier.fillMaxSize(),
				verticalArrangement = Arrangement.Center,
				horizontalAlignment = Alignment.CenterHorizontally,
			) {
					Text(
						viewModel.data.value,  // viewModel에 정의된 데이터 불러와서 사용
						fontSize = 30.sp,
					)
					Button(onClick = {
						viewModel.data.value = "World"
					}) {
							Text("변경")
						}
				}
		}
	}


class MainViewModel: ViewModel() {
	val data = mutableStateOf("Hello")  // remember 없이 데이터 정
}
  • gradle에 viewModel을 추가한 경우는 사용 방법이 다르니 참고!
  • 현재 위 코드처럼 view내부에서 viewModel의 데이터를 변경하는 것은 바람직하지 않기 때문에 아래 코드처럼 수정
class MainActivity : ComponentActivity() {
	private val viewModel by viewModels<MainViewModel>()  // viewModel 불러오기

	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
	
		setContent {
			Column(
				modifier =Modifier.fillMaxSize(),
				verticalArrangement = Arrangement.Center,
				horizontalAlignment = Alignment.CenterHorizontally,
			) {
					Text(
						viewModel.data.value,  // viewModel에 정의된 데이터 불러와서 사용
						fontSize = 30.sp,
					)
					Button(onClick = {
						// viewModel.data.value = "World" 외부 접근 금지를 해놓았으므로 여기서는 data 변경 불가능
						viewModel.changeValue() // viewModel에 작성한 변경 함수 불러오기
					}) {
							Text("변경")
						}
				}
		}
	}


class MainViewModel: ViewModel() {
	private val _data = mutableStateOf("Hello")  // 내부에서만 사용하도록 외부 접근 금지 
																							// mutableStateOf는 읽기와 쓰기 가능
	val data: State<String> = _data  // State 타입으로 정의해서 외부에서는 읽기전용으로 접근

	fun changeValue() {
		_data.value = "World"	
	}
}

 

 

 

💡ViewModel 과 Hoisting의 차이점

  • hoisting은 부모-자식 관계에서 데이터와 상태를 공유하는 것에 적합
  • viewModel은 보다 넓은 범위에서 사용하며 모든 컴포저블이 접근할 수 있음

 

 

 

 

🔥사진 출처 및 참고 자료

https://8iggy.tistory.com/271

 

Android | Jetpack Compose State Hoisting

읽기 전 불필요한 코드나 잘못 작성된 내용에 대한 지적은 언제나 환영합니다. 개인적으로 실습하면서 배운 점을 정리한 글입니다, Jetpack Compose의 State 코드랩과 Jetpack Compose State 공식문서의 내

8iggy.tistory.com

https://www.youtube.com/watch?v=Fn_xJ_IRHiA&list=PLxTmPHxRH3VV8lJq8WSlBAhmV52O2Lu7n&index=10