현재 Compose내에서 사용하는 State값은 2개
TextField에 사용 된 String 타입의 query
val (query, setQuery) = rememberSaveable { mutableStateOf("") }
LazyVerticalGrid에 결과 값으로 보일 list
val list = mutableStateListOf<Document>()
Textfield에 onValueChange()
이벤트 호출 마다
query state값을 변경해주는 setQuery()
가 호출되기 때문에 리컴포지션 된다
상태값을 저장(remember)하는 건 query
뿐
리컴포지션이 일어나면 query
는 유지되고 list
를 초기화 된다
리컴포지션이 일어나도 list
값이 유지 되는 것
저번 블로그 글에도 남겼지만
리스트 상태값에 대한 이해도가 없어서
remember{}
로 감싸면? 앱이 실행안되고 강제 종료행이였다..
자 그러면 공부 시작!
compose 상태관리 공식문서를 들어가 "list"로 키워드를 검색 해보자
빨간색 박스로 뭐라 무섭게 나와있다..
어색한 말을 좀 가공해서 쉽게 읽어보면..
ArrayList
or mutableListof()
와 같은 변경 가능한 List 객체를
state로 사용하면 잘못된 데이터 또는 오래된 데이터가 표시 될 수 있다.
..?..
변경 가능한 객체, ArrayList
와 같은 객체는 Compose에서 관찰 할 수 없고
객체가 변경 될 때 리컴포지션을 트리거하지 않습니다
..!..??????
그러니 변경은 가능하지만 관찰(observe)은 안되는 객체를 사용하지 마시고,
State<List<T>>
및 listOf()
같은 변경 불가능한 객체에
관찰 가능한 데이터 홀더를 사용하는 것이 좋습니다.
아 그러니깐 결론적으론 위에서 사용했던
mutableStateListOf<Document>()
로 사용하면
state 변경 감지도 못하고, 변경되도 리컴포지션을 트리거 하지 않는다..?
그러니깐 변경 불가능한 List객체 state로 사용하고 관찰해보자?
setContent {
val (query, setQuery) = rememberSaveable { mutableStateOf("") }
val list = mutableStateListOf<Document>()
...
SearchPage(
query = query, setQuery = setQuery,
onSearch = {
searchImage(query = query) {
val docs = it["documents"] as List<*>
for (doc in docs) {
val castedDoc =
Document.fromJson(json = doc as Map<String, Any>)
list.add(castedDoc)
}
}
},
results = list,
)
...
}
SearchPage
는 제가 만든 컴포저블 함수입니다.
Document
는 제가 만든 모델 객체 입니다
(remote API 호출 후 응답 값과 동일한 데이터 모델)
그러니 List<T>
제네릭 타입은 용도에 맞춰 바꿔서 사용하세요!
setContent {
val (query, setQuery) = rememberSaveable { mutableStateOf("") }
val list = rememberSaveable { mutableStateOf(listOf<Document>()) }
...
SearchPage(
query = query, setQuery = setQuery,
onSearch = {
searchImage(query = query) {
val results = it["documents"] as List<*>
val docs = mutableListOf<Document>();
for (result in results) {
val castedDoc =
Document.fromJson(json = result as Map<String, Any>)
docs.add(castedDoc)
}
list.value = docs
}
},
results = list.value,
)
...
}
listOf<T>
: list를 변경 불가능한 상태로 변경해줍니다
기존 String, Int 사용했던것과 마찬가지로 변경가능한 state 값으로 다루기 위해 mutableStateOf{}
감싸줍니다
그러고 화면을 전환해도 데이터가 유지 되도록 rememberSaveable{}
로 감싸줍니다
영상엔 담기지 않았지만
list 상태값 변경되었을 때 리컴포저블 하는 것과
화면에 보이는 대로 query가 변경되어 리컴포저블 되더라도
값을 remeber 되어 기존 값을 유지하는 것
성공적이다... !
당연히 list값을 상태 값으로 바라볼 수 있게끔 mutableStateListOf
가 있어서 기존에 사용했던 mutableStateOf를 못 쓰는 줄 알았는데 변경 불가능한 List 객체였다면 쓸 수 있었다.
변경가능한 객체를 상태로 바라볼 때 리컴포저블 트리거도 안되고 이슈가 많다면 왜 따로 함수까지 만들어줬을까? 의문이긴하지만
공식문서에 적힌대로 변경 불가능한 객체를 state를 observing(관찰)한다! 라는 핵심을 얻어가며 오늘 글을 마무리 지어본다.