컴포즈에서 회원가입이나 로그인과 같은 CRUD의 생성과 수정과 같은 작업에서 현재 사용자가 입력한 값들을 담고있는 변수들이 필요하다.
이를 주로 컴포즈함수에서 remember를 통해 값을 저장하는데 다음과 같이 코드가 매우 길어지고 불편하다!!
var userName by rememberSaveable { mutableStateOf("") }
var id by rememberSaveable { mutableStateOf("") }
var password by rememberSaveable { mutableStateOf("") }
var passwordCheck by rememberSaveable { mutableStateOf("") }
var phoneNumber by rememberSaveable { mutableStateOf("") }
var smsCode by rememberSaveable { mutableStateOf("") }
var userType by rememberSaveable { mutableStateOf(UserType.USER) }
var userNameError: String? by rememberSaveable { mutableStateOf(null) }
var idError: String? by rememberSaveable { mutableStateOf(null) }
var passwordError: String? by rememberSaveable { mutableStateOf(null) }
var passwordCheckError: String? by rememberSaveable { mutableStateOf(null) }
var phoneNumberError: String? by rememberSaveable { mutableStateOf(null) }
이를 data class로 재정의 한다.
data class LoginInputState(
val id: String = "",
val idError: String? = null,
val password: String = "",
val passwordError: String? = null,
val passwordVisible: Boolean = false,
val passwordIsRemove: Boolean = false,
) {
fun validateCopy() : LoginInputState{
return copy(
idError = if(id.isEmpty()){
"아이디를 입력해주세요"
}else{
null
},
passwordError = if(password.isEmpty()){
"비밀번호를 입력해주세요"
}else{
null
}
)
}
fun isValid() : Boolean{
return idError == null && passwordError == null
}
}
////
var inputState by rememberSaveable { mutableStateOf(LoginInputState()) }
문제가 잘 해결된거 같다. 컴파일후 실행해보면 ?
User
java.lang.IllegalArgumentException:
MutableState containing LoginInputState(id=,
idError=null, password=, passwordError=null,
passwordVisible=false, passwordIsRemove=false)
cannot be saved using the current SaveableStateRegistry.
The default implementation only
supports types which can be stored inside the Bundle.
Please consider implementing a custom Saver for
this class and pass it as a stateSaver parameter to rememberSaveable().
아.
rememberSavable은 Bundle를 통해 데이터가 저장되는데 이를 처리해주라고 한다.
remember를 사용하면 해결된다.
하지만 화면전환시에 데이터가 사라지는걸 막으려면
직렬화, 역직렬화를 위해서 클래스에서 Parcelable 인터페이스를 구현해 주어야한다...!!
그러나 구글에서 어노테이션 기반 자동생성을 이미 만들어두었다.
plugins {
id("kotlin-parcelize")
}
build.gradle에 플러그인을 추가해주자
이제 @Parcelize만 사용해주면
override fun describeContents(): Int {
TODO("Not yet implemented")
}
override fun writeToParcel(dest: Parcel, flags: Int) {
TODO("Not yet implemented")
}
해당 부분의 보일러플레이트코드가 공짜다.
@Parcelize
data class LoginInputState(
val id: String = "",
val idError: String? = null,
val password: String = "",
val passwordError: String? = null,
val passwordVisible: Boolean = false,
val passwordIsRemove: Boolean = false,
) : Parcelable {
fun validateCopy() : LoginInputState{
return copy(
idError = if(id.isEmpty()){
"아이디를 입력해주세요"
}else{
null
},
passwordError = if(password.isEmpty()){
"비밀번호를 입력해주세요"
}else{
null
}
)
}
fun isValid() : Boolean{
return idError == null && passwordError == null
}
}
/////적용코드
var inputState by rememberSaveable { mutableStateOf(LoginInputState()) }
inputState = inputState.validateCopy()
if(inputState.isValid().not()){
return@CommonButton
}
val params = LoginParams(
email = inputState.id,
password = inputState.password
)
coroutineComposeScope.launch {
val resp = viewModel.emailLogin(params)
if(resp){
onLoginSuccess()
}
}
이제 코드가 매우 줄어들었다!