Compose 상태관리 (2)

푸른하늘·2022년 6월 28일
0

컴포즈

목록 보기
2/5
post-thumbnail

이야기 할 주제

  • 변수를 저장하는 방법
  • Compose ViewModel

🍎상태 및 컴포지션

Compose를 업데이트하는 유일한 방법은 새 인수로 동일한 컴포저블을 호출하는 것입니다. 이러한 인수는 UI 상태를 표현합니다. 상태가 업데이트될 때마다 재구성이 실행됩니다.

@Composable
fun HelloContent() {
   Column(modifier = Modifier.padding(16.dp)) {
       Text(
           text = "Hello!",
           modifier = Modifier.padding(bottom = 8.dp),
           style = MaterialTheme.typography.h5
       )
       OutlinedTextField(
           value = "",
           onValueChange = { },
           label = { Text("Name") }
       )
   }
}

간단한 코드이다

  • Composable 함수로써 HelloCountent() 생성한 함수이다
  • Column 안에Text 와OutlineTextFile 가 있다

하지만 TextFiled는 자동으로 업데이트가 되지 않는다

왜?

  • TextField가 자체적으로 업데이트가 되지 않기 때문이며, value 매개 변수가 변경될 때만 업데이트 되기 때문이다 . 이는 리컴포지션 작동 방식이다.

리컴포지션

  • 데이터가 변경될 때 컴포지션을 업데이트하기 위해 컴포저블을 다시 실행하는 것을 말합니다.

🍎컴포저블의 상태

remember 컴포저블을 사용하여 메모리에 단일 객체를 저장할 수 있습니다.
remember에 계산된 값은 초기 포지션 중에
컴포지션에 저장되고 또 저장된 값을 리컴포지션 중에 반환합니다.

주로 사용되는 remember 선언하는 방법 3가지

val 변수이름 = remember { mutableStateOf(default) } // 주로 사용
var 변수이름 by remember { mutableStateOf(default) }
val (변수이름, 받는변수이름) = remember { mutableStateOf(default) } // React형식 비슷

if 문을 통해 컴포저블 변경

@Composable
fun HelloContent() {
   Column(modifier = Modifier.padding(16.dp)) {
       var name by remember { mutableStateOf("") }
       if (name.isNotEmpty()) {
           Text(
               text = "Hello, $name!",
               modifier = Modifier.padding(bottom = 8.dp),
               style = MaterialTheme.typography.h5
           )
       }
       OutlinedTextField(
           value = name,
           onValueChange = { name = it },
           label = { Text("Name") }
       )
   }
}

코드 설명

  • HelloCount() 함수 선언후 Column을 사용하여 Text, OutlineTextField 나눈다
  • 두 번째 mutableStateOf 선언 방식 사용하여 name 변수 만들기
  • if문을 걸어서 변수 name이 isNotEmpty() 일 때만 Text 함수 실행하여 name값을 삽입한다

하지만 remember 과정 전체의 상태르 유지하는데 도움이 되지만 구성 변경 전반에 상태가 유지가 되지 않는다. 이경우 rememberSaveable을 사용해야 합니다

rememberSaveable : Bundle에 저장할 수 있는 모든 값을 자동으로 저장합니다.

🍎 상태호이스팅

상태호이스팅

  • Compose에서 Stateless로 들기 위해 상태를 컴포저블의 호출자로 옮기는 패턴입니다.

Stateless

  • 상태를 갖지 않는 컴포저블

StatFul

  • 함수 내부적으로 변수 상태를 보존하고 수정하는 상태

표시할 현재의 값

  • value: T

T가 제안된 새 값인 경우 값을 변경하도록 하는 요청 이벤트

  • onValueChange: T -> Unit: T

🍎 상태호이스팅 중요한 속성

단일 소스 저장소

  • 상태를 복제하는 대신 옮겼기 때문에 소스 저장소가 하나만 있습니다.

캡슐화됨

  • 스테이트풀(Stateful) 컴포저블만 상태를 수정할 수 있습니다.

공유 가능함

  • 호이스팅한 상태를 여러 컴포저블과 공유할 수 있습니다.

가로채기 가능함

  • 스테이트리스(Stateless) 컴포저블의 호출자는 상태를 변경하기 전에 이벤트를 무시할지 수정할지 결정할 수 있습니다.

분리됨

  • 스테이트리스(Stateless) ExpandingCard의 상태는 어디에나 저장할 수 있습니다.
@Composable
fun HelloScreen() {
    var name by rememberSaveable { mutableStateOf("") }

    HelloContent(name = name, onNameChange = { name = it })
}

@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello, $name",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.h5
        )
        OutlinedTextField(
            value = name,
            onValueChange = onNameChange,
            label = { Text("Name") }
        )
    }
}

코드 해설

  • HelloContent 함수안에 name 과 , onNameChange 가 되었을때를 매개변수로 받습니다
  • Column 안에 Text , OutlineTextFiled를 나눕니다
  • 매개변수로 받는 name을 -> Text $name 위치 / label "

이점

상태의 저장 방식과 분리됩니다. 분리된다는 것은 HelloScreen을 수정하거나 교체할 경우 HelloContent의 구현 방식을 변경할 필요가 없다는 의미입니다.

🍎ViewModel 및 상태 홀더

  • 위에 영상이랑 동작은 같다!!

ViewModel 이점

  • ViewModel에 의해 트리거된 작업이 구성 변경에도 그대로 유지됩니다.
  • 백 스택에서 사라질 때 ViewModel도 삭제되기 때문에, 상태가 자동으로 정리됩니다.
  • 화면이 백 스택에 있는 동안 Navigation이 ViewModel을 캐시합니다.
  • Hilt와 같은 다른 Jetpack 라이브러리와의 통합
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            HelloScreen(HelloViewModel())
        }
    }
}

class HelloViewModel() : ViewModel() {

    private val _name = MutableLiveData("")
    val name: LiveData<String> = _name

    fun onNameChanged(newName: String){
        _name.value = newName
    }
}

@Composable
fun HelloScreen(helloViewModel: HelloViewModel ) {
    val name by helloViewModel.name.observeAsState("")
    HelloContent(name = name, onNameChange = { helloViewModel.onNameChanged(it)})
}

@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {


    Column(modifier = Modifier.padding(16.dp)) {
        if (name.isNotEmpty()) {
            Text(
                text = "Hello, $name",
                modifier = Modifier.padding(bottom = 8.dp),
                style = MaterialTheme.typography.h5
            )
        }

        OutlinedTextField(
            value = name,
            onValueChange = onNameChange,
            label = { Text("Name") }
        )
    }
}
profile
Developer-Android-CK

0개의 댓글