
Jetpack Compose ๊ฐ์ ์ ์ธํ UI๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ๋ฐ์๋ ์ํ(State)๋ฅผ ๊ธฐ์ค์ผ๋ก ํ๋ฉด์ ๊ทธ๋ฆฝ๋๋ค.
๊ธฐ์กด์ ๋ช
๋ นํ UI(์: findViewById, setVisibility)์์๋
"๋ฒํผ์ ๋๋ฅด๋ฉด ์ด ๋ทฐ๋ฅผ ์จ๊ธฐ๊ณ , ๋ค๋ฅธ ๋ทฐ๋ฅผ ๋ณด์ฌ์ค๋ค"๋ผ๋ ์์ผ๋ก UI ์กฐ์ ๋ก์ง์ ์ง์ ์์ฑํด์ผ ํ์ต๋๋ค.
ํ์ง๋ง ์ ์ธํ UI์์๋
๐ "ํ์ฌ ์ํ๊ฐ Loading์ด๋ฉด ๋ก๋ฉ ํ๋ฉด์ ๊ทธ๋ ค๋ผ"
๐ "ํ์ฌ ์ํ๊ฐ Success๋ผ๋ฉด ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ์ค๋ผ"
๐ "ํ์ฌ ์ํ๊ฐ Error๋ผ๋ฉด ์๋ฌ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํด๋ผ"
์ฆ, UI๋ ์ํ์ ์ค๋
์ท์ ๊ทธ๋ฆฌ๋ ๋ฐฉ์์ผ๋ก ๋ฐ๋์์ต๋๋ค.
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ํ๋ฅผ ์ด๋ป๊ฒ ์ ์ํ๋๋๊ฐ ์ฑ์ ๊ตฌ์กฐ์ ์์ ์ฑ์ ํฐ ์ํฅ์ ๋ฏธ์นฉ๋๋ค.
์ฒ์์๋ ๋ง์ ๋ถ๋ค์ด ์ด๋ ๊ฒ ์๊ฐํฉ๋๋ค.
"์ํ๋ฅผ ํํํ๋ค๋ฉด Enum์ด ๋ฑ์ด์ง ์๋? ๊ฐ๋ง ๊ตฌ๋ถํ๋ฉด ๋์์?"
enum class NetworkStatus(val code: Int, val description: String) {
LOADING(0, "Loading..."),
SUCCESS(200, "Request succeeded"),
ERROR(500, "Internal server error");
}
์ด ์ฝ๋๋ ์ผํ ๋ณด๋ฉด ๊ทธ๋ด์ธํฉ๋๋ค.
๋คํธ์ํฌ ์์ฒญ์ ์ธ ๊ฐ์ง ์ํ๋ฅผ ์ ํํํ๊ณ ์๊ณ , ์ซ์ ์ฝ๋๋ ๋ถ์ผ ์ ์์ฃ .
ํ์ง๋ง ์ค์ UI๋ฅผ ๋ง๋ค๋ค ๋ณด๋ฉด ๊ธ๋ฐฉ ํ๊ณ๋ฅผ ๋๋ผ๊ฒ ๋ฉ๋๋ค.
SUCCESS ์ํ์์๋ ์๋ฒ์์ ๋ด๋ ค์ค ๋ฐ์ดํฐ๋ฅผ UI์ ๋๊ฒจ์ค์ผ ํฉ๋๋ค. ERROR ์ํ์์๋ ๋จ์ ์ฝ๋(500)๋ฟ ์๋๋ผ, ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ค ๋ฉ์์ง๋ ์์ธ ๊ฐ์ฒด๋ ํ์ํฉ๋๋ค. Enum์ ๋ชจ๋ ์์๊ฐ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ ธ์ผ ํ๋ฏ๋ก,
์ํ๋ง๋ค ๋ค๋ฅธ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๊ฐ๊ฒ ํ๊ธฐ๊ฐ ์ฌ์ค์ ๋ถ๊ฐ๋ฅํฉ๋๋ค.
UI State๋ ๋ณดํต "์ ํด์ง ๋ช ๊ฐ์ง ์ํ"๋ง ์์ผ๋ฉด ์ถฉ๋ถํฉ๋๋ค.
์๋ฅผ ๋ค์ด ๋ก๊ทธ์ธ ํ๋ฉด์ด๋ผ๋ฉด
์ด ์ ๋๋ฉด ๋์
๋๋ค.
๊ทธ๋ฐ๋ฐ Enum์ ๋ณธ์ง์ ์ผ๋ก "์ด๋ฆฐ ๊ตฌ์กฐ"๋ผ๊ธฐ๋ณด๋ค๋, ์ํ๋ณ๋ก ๋ฐ์ดํฐ๊น์ง ๋ค๋ฃจ๊ธฐ์๋ ๋๋ฌด ๋จ์ํ ํ์ด์ฃ .
์ฆ, Enum์ UI State๋ฅผ ํํํ๊ธฐ์ ํํ๋ ฅ์ด ๋ถ์กฑํฉ๋๋ค.
๊ทธ๋์ ๋ฑ์ฅํ๋ ๊ฒ sealed class์
๋๋ค.
sealed class๋ ๋ซํ ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๋ฉฐ, ์ํ์ ๋ฐ์ดํฐ๋ฅผ ํจ๊ป ์ ์ํ ์ ์์ต๋๋ค.
sealed class LoginUiState {
object Idle : LoginUiState()
object Loading : LoginUiState()
data class Success(val userName: String) : LoginUiState()
data class Error(val message: String, val code: Int? = null) : LoginUiState()
}
์ฌ๊ธฐ์ ์ฃผ๋ชฉํ ์ ์,
๊ฐ ์ํ๊ฐ ์๊ธฐ์๊ฒ ํ์ํ ๋ฐ์ดํฐ๋ง ์ ์ํ ์ ์๋ค๋ ๊ฒ์
๋๋ค.
Loading โ ๋ณ๋ ๋ฐ์ดํฐ ํ์ ์์ Success โ ์ฌ์ฉ์ ์ด๋ฆ ํ์ Error โ ๋ฉ์์ง์ ์๋ฌ ์ฝ๋ ํ์ when (uiState) {
is LoginUiState.Idle -> IdleScreen()
is LoginUiState.Loading -> LoadingScreen()
is LoginUiState.Success -> WelcomeScreen(uiState.userName)
is LoginUiState.Error -> ErrorScreen(uiState.message)
}
when ๊ตฌ๋ฌธ์์ ์ปดํ์ผ๋ฌ๊ฐ ๋ชจ๋ ์ํ๋ฅผ ๊ฐ์ ์ฒดํฌํด์ฃผ๊ธฐ ๋๋ฌธ์,๐ ์ฆ, sealed class๋ UI State๋ฅผ ํํํ ๋ ์์ ์ฑ๊ณผ ๊ฐ๋
์ฑ์ ๋์์ ํ๋ณดํ ์ ์์ต๋๋ค.
sealed interface๋ sealed class์ ๊ฑฐ์ ๋น์ทํ์ง๋ง, ๋ค์ค ์์์ด ๊ฐ๋ฅํ๋ค๋ ์ ์์ ๋ ์ ์ฐํฉ๋๋ค.
sealed interface UiState
object Loading : UiState
data class Success(val data: List<String>) : UiState
data class Error(val message: String) : UiState
interface Loggable {
val log: String
}
data class Error(
val message: String,
override val log: String
) : UiState, Loggable
์ด๋ ๊ฒ ํ๋ฉด Error๋ UI State์ด๋ฉด์ ๋์์ Loggableํ ์ฑ๊ฒฉ๋ ๊ฐ์ง ์ ์์ต๋๋ค.
์ฆ, ์ํ๋ฅผ ๋ค์ํ ๋งฅ๋ฝ์์ ์ฌ์ฌ์ฉํ ์ ์๋ ํ์ฅ์ฑ์ ์ ๊ณตํฉ๋๋ค.
์ฌ๊ธฐ์ ํต์ฌ์ sealed๋ผ๋ ํค์๋ ์์ฒด์
๋๋ค.
์ผ๋ฐ class๋ interface๋ ์ด๋์๋ ์์/๊ตฌํ์ด ๊ฐ๋ฅํฉ๋๋ค.
์ฆ, ์ํ ์งํฉ์ด ์ด๋ ค(Open) ์์ด์ ์ธ๋ถ์์ ์๋ก์ด ํ์ ํ์
์ด ์ถ๊ฐ๋ ์ ์์ฃ .
UI State์์ ์ด๋ฐ ๊ฒ ์ํํฉ๋๋ค.
๋ก๊ทธ์ธ ํ๋ฉด์ ์ํ๋ Idle, Loading, Success, Error๋ง ์์ผ๋ฉด ๋๋๋ฐ,
๋๊ตฐ๊ฐ ์ธ๋ถ ๋ชจ๋์์ HalfSuccess ๊ฐ์ ์ด์ํ ์ํ๋ฅผ ์ถ๊ฐํด๋ฒ๋ฆฌ๋ฉด?
๐ when ๋ถ๊ธฐ์์ ์ฒ๋ฆฌํ์ง ๋ชปํ ์ํ๊ฐ ์๊ฒจ, ๋ฐํ์ ์๋ฌ๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
sealed๋ฅผ ์ฐ๋ฉด:
when์์ ๋ชจ๋ ์ํ๋ฅผ ๊ฐ์ ์ฒดํฌ โ ๋๋ฝ ๋ฐฉ์ง ๐ ์ ๋ฆฌํ์๋ฉด, sealed์ ๊ฐ์ฅ ํฐ ์๋ฏธ๋ โ์ฌ๊ธฐ ์ ์๋ ์ํ ์ธ์๋ ์๋คโ๋ฅผ ๋ณด์ฅํ๋ ๊ฒ์
๋๋ค.
์ด ๋๋ถ์ UI State๋ฅผ ์ ์ํ ๋ sealed class/interface๊ฐ ๋น์ ๋ฐํฉ๋๋ค โจ
enum โ ๋จ์ ์ํ ๊ตฌ๋ถ์ ์ ํฉ (์: Theme { LIGHT, DARK }) sealed class โ ์ํ + ๋ฐ์ดํฐ๋ฅผ ํํํ ์ ์์ด UI State ๊ด๋ฆฌ์ ์ต์ sealed interface โ ๋คํ์ฑ๊ณผ ํ์ฅ์ฑ์ด ํ์ํ ์ํฉ์์ ์ ๋ฆฌ sealed โ ์ํ ์งํฉ์ ๋ซ์์ฃผ๊ณ , ์ปดํ์ผ๋ฌ๊ฐ ๋ชจ๋ ๊ฒฝ์ฐ๋ฅผ ๊ฐ์ ์ฒดํฌํ๊ฒ ํด์ค ๐ Compose์์ UI State๋ฅผ ์ ์ํ ๋๋
enum๋ณด๋ค sealed class/interface๋ฅผ ์ฐ๋ ๊ฒ์ด ํจ์ฌ ์์ ํ๊ณ ํํ๋ ฅ์ด ํ๋ถํฉ๋๋ค ๐ก
UI State๋ ๊ณง ์ฑ์ ์์ ์ฑ๊ณผ ์ง๊ฒฐ๋๋ ํต์ฌ ์์์
๋๋ค.
์์ ์ ํ ํ๋๊ฐ ์ ์ฒด ์ํคํ
์ฒ์ ํ์ง์ ํฌ๊ฒ ๋ฐ๊ฟ ์ ์์ต๋๋ค ๐