Stateless한 Compose의 TextField
TextField란 텍스트를 입력하는 UI이다. 이 UI는 두가지 부분으로 구성된다.
- 텍스트를 입력하는 부분(User Interaction)
- 텍스트를 저장하는 부분(State)
텍스트를 입력하려면 TexrField에 입력된 Text의 상태(State)가 있어야 한다. 기존의 xml에서의 TextField는 Stateful해서 자신의 Text 상태를 직접 저장했다. 즉 위 두가지 부분이 모두 TextField에 존재했다.
하지만, Compose는 Stateless하기 때문에 TextField에는 Text의 상태를 저장하는 공간이 없다. 즉, Compose의 TextField는 텍스트를 입력하는 부분만 있고, 텍스트를 저장하는 부분이 없다.
Textfield State만들기
그렇다면 우리는 Compose의 TextField를 위한 State를 만들어주어야 한다. 한 번 아래와 같이 mutableState를 이용해 TextField의 state를 만들어보자.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val textState = mutableStateOf("")
TextField(value = textState.value, onValueChange = { textValue -> textState.value = textValue })
}
}
}
위 코드가 어떻게 동작할거 같은가? 직관적으로는 onValueChange에서 textValue가 바뀔 때 textState에 세팅되기 때문에 입력값이 나올 것처럼 보인다.
하지만 결과는 다음과 같다.
아무리 눌러도 textField가 바뀌지 않는 이유는 Recomposition에 있다.
Compose는 TextField의 상태가 바뀔 때마다 Recompose라는 것을 하게 된다. Recompose가 일어나면 setContent{}블록의 처음부터 끝까지가 다시 수행되게 되는데 이때 textState가 다시 mutableStateOf("")로 할당되어 문제가 생기는 것이다.
remember 이용하여 State저장하기
이에 따라 우리는 Recompose가 일어나기 전 State를 저장하고 Recompose가 일어났을 때 복구하는 것이 필요하다. Compose에서는 이를 remember을 이용해 하는 것이 가능하다.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val textState = remember {
mutableStateOf("")
}
TextField(value = textState.value, onValueChange = { textValue -> textState.value = textValue })
}
}
}
remember을 이용하면 Recompose가 일어날 때 textState의 State가 복구된다. 따라서 아래와 같은 결과가 나오게 된다.