์ฑ๋ฅ๊ณผ ๋ฆฌ์ปดํฌ์ง์ ์ต์ ํ - derivedStateOf์ Stable
์ฒซ ๊ธ์์ ๋ฆฌ์ปดํฌ์ง์ ์ "State๋ก ์ ์ธ๋ ๊ฐ์ ์ฝ๊ณ ์๋ ์ปดํฌ์ ๋ธ์ด, ๊ทธ ๊ฐ์ด ๋ฐ๋๋ฉด ๋ค์ ์คํ๋๋ ๊ฒ"์ด๋ผ๊ณ ํ๋ค. ๊ทผ๋ฐ ์ด๋ค ๊ฐ์ "์ฝ๊ธฐ๋ง" ํด๋ ๋ฆฌ์ปดํฌ์ง์ ์ด ์๊ฐ๋ณด๋ค ์์ฃผ ์ผ์ด๋ ์ ์๋ค. ๋ชฉ๋ก์ ์คํฌ๋กคํ ๋๋ง๋ค "๋งจ ์๋ก" ๋ฒํผ์ ๋ณด์ฌ์ค์ง ๋ง์ง ํ๋จํ๋ ๊ฑธ๋ก ํ์ธํด๋ณด์.
์คํฌ๋กค ์์น๋ฅผ ๋ณด๊ณ ๋ฒํผ์ ๋ณด์ฌ์ฃผ๋ ์ฝ๋
@Composable
fun TodoListScreen(todoList: List<Todo>) {
val listState = rememberLazyListState()
val showScrollToTop = listState.firstVisibleItemIndex > 0
Column {
if (showScrollToTop) {
Button(onClick = { /* ๋งจ ์๋ก ์คํฌ๋กค */ }) {
Text("๋งจ ์๋ก")
}
}
LazyColumn(state = listState) {
items(todoList, key = { it.id }) { todo ->
// ...
}
}
}
}๋์์ ํ๋ค. ๊ทผ๋ฐ Layout Inspector์ ๋ฆฌ์ปดํฌ์ง์
์นด์ดํธ ํ์๋ฅผ ์ผ๊ณ ์คํฌ๋กค์ ํด๋ณด๋ฉด, TodoListScreen ์ ์ฒด๊ฐ ์คํฌ๋กคํ๋ ๋์ ๊ณ์ ๋ฆฌ์ปดํฌ์ง์
๋๋ค. showScrollToTop์ true/false ๋ ์ค ํ๋๋ก, ์ค์ ๋ก ๋ฐ๋๋ ๊ฑด "๋งจ ์ ๊ทผ์ฒ๋ ์๋๋"์ ๊ฒฝ๊ณ๋ฅผ ๋์ ๋ ๋ฑ ํ ๋ฒ๋ฟ์ธ๋ฐ, ๊ทธ๋ณด๋ค ํจ์ฌ ์์ฃผ ๋ค์ ๊ทธ๋ ค์ง๊ณ ์๋ค.
์ ์ด๋ ๊ฒ ์์ฃผ ๋ฆฌ์ปดํฌ์ง์ ๋ ๊น
listState.firstVisibleItemIndex๋ ์คํฌ๋กค ์ค์ ๋งค ํ๋ ์ ๋ฐ๋๋ ๊ฐ์ด๋ค. val showScrollToTop = listState.firstVisibleItemIndex > 0์ด๋ผ๊ณ ์ฐ๋ฉด, ์ปดํฌ์ฆ๋ ์ด ์ค์ด ์๋ ์ปดํฌ์ ๋ธ(TodoListScreen)์ด firstVisibleItemIndex๋ฅผ ์ฝ๊ณ ์๋ค๋ ๊ฑธ ๊ธฐ๋กํ๋ค. ๊ทธ ๊ฐ์ด ์คํฌ๋กค๋ง๋ค ๋ฐ๋๋๊น, ๋งค๋ฒ TodoListScreen์ ํต์งธ๋ก ๋ค์ ์คํํ๋ค. showScrollToTop์ด๋ผ๋ ๊ฒฐ๊ณผ๊ฐ ์์ฒด๊ฐ true์์ true๋ก ์ ๋ฐ๋์ด๋, ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๊ณ์ฐํ๋ ๋ฐ ์ด ์ฌ๋ฃ(firstVisibleItemIndex)๊ฐ ๋ฐ๋๋ฉด ์ผ๋จ ๋ค์ ๊ณ์ฐ๋ถํฐ ํ๋ ๊ฑฐ๋ค.
derivedStateOf - "๊ฒฐ๊ณผ๊ฐ ์ค์ ๋ก ๋ฐ๋ ๋๋ง" ์๋ฆฐ๋ค
val showScrollToTop by remember {
derivedStateOf { listState.firstVisibleItemIndex > 0 }
}derivedStateOf { }๋ ์์ ๋๋ค๋ฅผ ๊ณ์ ์คํํด์ ๊ฐ์ ๊ณ์ฐํ๊ธด ํ์ง๋ง, ๊ทธ ๊ฒฐ๊ณผ๊ฐ์ด ์ค์ ๋ก ๋ฐ๋ ๋๋ง "์ด ๊ฐ์ ์ฝ๊ณ ์๋ ์ปดํฌ์ ๋ธ์ ๋ค์ ๊ทธ๋ ค์ผ ํ๋ค"๋ ์ ํธ๋ฅผ ๋ด๋ณด๋ธ๋ค. ๋๋ค ์์์๋ ์ฌ์ ํ firstVisibleItemIndex๋ฅผ ๋งค ํ๋ ์ ์ฝ์ง๋ง, 0์์ 3, 3์์ 7๋ก ๋ฐ๋์ด๋ showScrollToTop ๊ฐ ์์ฒด๋ ๊ณ์ true๋ผ์ ๋ฐ๋์ง ์์๋ค๋ ๊ฑธ ์๊ณ ์์ผ๋, ๊ทธ ๊ฒฝ๊ณ๊ฐ์ ๋๊ธฐ ์ ๊น์ง๋ TodoListScreen์ ๋ค์ ๊ทธ๋ฆฌ์ง ์๋๋ค.
์๋ฌด ๋๋ derivedStateOf๋ฅผ ์ฐ๋ฉด ๋๋ ๊ฑด ์๋๋ค
๊ณ์ฐ์ด ์์ฃผ ๊ฐ๋ณ๊ณ , ์๋ณธ ๊ฐ์ด ๋ฐ๋ ๋ ๊ฒฐ๊ณผ๊ฐ๋ ๊ฑฐ์ ํญ์ ๊ฐ์ด ๋ฐ๋๋ค๋ฉด derivedStateOf๋ฅผ ์ฐ๋ ์ค๋ฒํค๋๊ฐ ์คํ๋ ค ์ํด์ผ ์ ์๋ค. "์์ฃผ ๋ฐ๋๋ ๊ฐ์ผ๋ก๋ถํฐ, ๋๋ฌผ๊ฒ ๋ฐ๋๋ ๊ฒฐ๊ณผ๊ฐ์ ๋ฝ์๋ผ ๋"๊ฐ derivedStateOf๋ฅผ ์ธ ์๋ฆฌ๋ค. ์ง๊ธ ์์ ์ฒ๋ผ "๋งค ํ๋ ์ ๋ฐ๋๋ ์คํฌ๋กค ์์น"์์ "๊ฑฐ์ ์ ๋ฐ๋๋ ๋ถ๋ฆฐ ๊ฐ"์ ๋ฝ์๋ด๋ ๊ฒ ์ ํํ ์ด๋ฐ ๊ฒฝ์ฐ๋ค.
Stable - ์ปดํฌ์ฆ๊ฐ "์ด๊ฑด ๋น๊ตํด์ ๊ฑด๋๋ธ ์ ์๋ค"๊ณ ๋ฏฟ๊ฒ ํด์ฃผ๊ธฐ
@Composable
fun TodoListScreen(todoList: List<Todo>) { ... }List<Todo>์ฒ๋ผ ์ฝํ๋ฆฐ ํ์ค List ์ธํฐํ์ด์ค๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์ผ๋ฉด, ์ปดํฌ์ฆ ์ปดํ์ผ๋ฌ๋ ์ด๊ฒ ์ค์ ๋ก ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ(immutable) ๋ฆฌ์คํธ์ธ์ง ํ์ ํ ์ ์๋ค. ๋ค์์ ArrayList ๊ฐ์ ๊ฐ๋ณ ๊ตฌํ์ฒด๊ฐ ๋ชฐ๋ ๋ค์ด์์ ๋ด์ฉ์ด ๋ฐ๋ ์๋ ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ด๋ ๊ฒ "์์ ํ๋ค๊ณ ํ์ ๋ชป ํ๋" ํ์
์ @Stableํ์ง ์๋ค๊ณ ๋ณด๊ณ , ์ปดํฌ์ฆ๊ฐ "์ด์ ๊ฐ๊ณผ ๋๊ฐ์ผ๋ ๋ฆฌ์ปดํฌ์ง์
๊ฑด๋๋ฐ๊ธฐ" ์ต์ ํ๋ฅผ ํฌ๊ธฐํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค.
๋ฐ์ดํฐ ํด๋์ค์ @Immutable ์ ๋
ธํ
์ด์
์ ์ง์ ๋ถ์ด๊ฑฐ๋, kotlinx.collections.immutable์ ImmutableList ๊ฐ์ "์ง์ง๋ก ์ ๋ฐ๋๋ค๊ณ ํ์
์ผ๋ก ๋ณด์ฅํ๋" ์ปฌ๋ ์
์ ์ฐ๋ฉด ์ปดํฌ์ฆ๊ฐ ๋ ํ์ ์ ๊ฐ๊ณ ๊ฑด๋๋ธ ์ ์๋ค. ์ง๊ธ ๋จ๊ณ์์ todo_project ๊ท๋ชจ๋ผ๋ฉด ๋น์ฅ ์ด๊ฑธ ๋ฐ๊ฟ ํ์๋ ์์ง๋ง, ๋ฆฌ์คํธ๊ฐ ์ปค์ง๊ณ ํ๋ฉด์ด ๋ณต์กํด์ง์๋ก ์ด ์ฐจ์ด๊ฐ ์ฒด๊ฐ๋๋ค.
Layout Inspector๋ก ์ง์ ํ์ธํ๊ธฐ
Android Studio์ Layout Inspector์๋ ๋ฆฌ์ปดํฌ์ง์
ํ์๋ฅผ ์์ผ๋ก ๋ณด์ฌ์ฃผ๋ ๊ธฐ๋ฅ์ด ์๋ค. derivedStateOf๋ฅผ ์ ์ฉํ๊ธฐ ์ /ํ๋ก ์คํฌ๋กคํ๋ฉด์ ์ด ์นด์ดํธ๋ฅผ ๋น๊ตํด๋ณด๋ฉด, "์ด ๋ณํ๊ฐ ์ง์ง ํจ๊ณผ๊ฐ ์์๋์ง"๋ฅผ ๊ฐ์ผ๋ก ๋๋ ค๋ง์ถ์ง ์๊ณ ๋์ผ๋ก ํ์ธํ ์ ์๋ค.
์ ๋ฆฌ
- ์ด๋ค ๊ฐ์ "์ฝ๊ธฐ๋ง" ํด๋, ๊ทธ ๊ฐ์ด ์์ฃผ ๋ฐ๋๋ฉด ๊ทธ๊ฑธ ์ฝ๋ ์ปดํฌ์ ๋ธ๋ ์์ฃผ ๋ฆฌ์ปดํฌ์ง์ ๋๋ค
derivedStateOf๋ "์์ฃผ ๋ฐ๋๋ ๊ฐ์์, ๋๋ฌผ๊ฒ ๋ฐ๋๋ ๊ฒฐ๊ณผ"๋ฅผ ๋ฝ์๋ผ ๋ ๋ฆฌ์ปดํฌ์ง์ ์ ์ค์ฌ์ค๋ค- ๋ฆฌ์คํธ/์ปฌ๋ ์ ํ์ ์ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์ ๋๋ ์ปดํฌ์ฆ๊ฐ "์์ ํ๊ฒ ๊ฑด๋๋ธ ์ ์๋ ํ์ "์ธ์ง๋ ์ฑ๋ฅ์ ์ํฅ์ ์ค๋ค
- ๊ฐ์ผ๋ก ํ๋จํ์ง ๋ง๊ณ Layout Inspector์ ๋ฆฌ์ปดํฌ์ง์ ์นด์ดํธ๋ก ํ์ธํ๋ค
๋ค์ ๊ธ์์๋ ํฐ๊ณผ ํ๋ธ๋ฆฟ์ฒ๋ผ ํ๋ฉด ํฌ๊ธฐ๊ฐ ๋ค๋ฅธ ๊ธฐ๊ธฐ์ ๋ง์ถฐ ๋ ์ด์์์ ๋ฐ๊พธ๋ ๋ฐฉ๋ฒ์ ๋ณด๊ฒ ๋ค.
