I have been trying to figure out how to hoist multiple states in 1 single composable/ viewModel but without any luck.
Whenever I type in one of the fields, it types in all fields at the same time. Like this: https://gyazo.com/b3aae51a92a00478dd228f69dc8c12ac
Also, if I add extra parameters to the UI composable (UserProfile), it gives me an error in the hoisted composable since its missing in both Userprofile inside UserProfileState. I know how to hoist 1 state but with mutiple it seems to become more complex. How can I hoist mutiple states in the same composable/ ViewModel ?
My Hoisted state composable:
@Composable
fun UserProfileState() {
var username by remember { mutableStateOf("") }
var email by remember { mutableStateOf("") }
UserProfile(
currentUserName = username,
newTextFieldValueUserName = { username = it })
UserProfile(
currentUserName = email,
newTextFieldValueUserName = { email = it},
)
}
UserProfile containing both Username and Email textfields:
@Composable
fun UserProfile(
currentUserName: String,
newTextFieldValueUserName: (String) -> Unit,
) { // Username and Email is placed here, as seen below!}
Username:
Spacer(modifier = Modifier.height(20.dp))
OutlinedTextField(
value = currentUserName,
onValueChange = newTextFieldValueUserName,
label = { Text(text = "Name") },
singleLine = true,
leadingIcon = {
Icon(
imageVector = Icons.Default.Email,
contentDescription = null
)
},
modifier = Modifier
.fillMaxWidth(180F),
)
Email:
Spacer(modifier = Modifier.height(20.dp))
OutlinedTextField(
value = currentUserName,
onValueChange = newTextFieldValueUserName,
label = { Text(text = "Email") },
singleLine = true,
leadingIcon = {
Icon(
imageVector = Icons.Default.Email,
contentDescription = null
)
},
modifier = Modifier
.fillMaxWidth(180F),
)
CodePudding user response:
You just add all the data you want to pass in as inputs, and you also add callback functions for all the data that can change inside the composable, for your example it would be like this
@Composable
fun UserProfile(
username: String,
email: String,
onUsernameChange: (String) -> Unit,
onEmailChange: (String) -> Unit,
) {
Column {
Spacer(modifier = Modifier.height(20.dp))
OutlinedTextField(
value = username,
onValueChange = onUsernameChange,
label = { Text(text = "Name") },
singleLine = true,
leadingIcon = {
Icon(
imageVector = Icons.Default.Email,
contentDescription = null
)
},
modifier = Modifier
.fillMaxWidth(180F),
)
Spacer(modifier = Modifier.height(20.dp))
OutlinedTextField(
value = email,
onValueChange = onEmailChange,
label = { Text(text = "Email") },
singleLine = true,
leadingIcon = {
Icon(
imageVector = Icons.Default.Email,
contentDescription = null
)
},
modifier = Modifier
.fillMaxWidth(180F),
)
}
}
Then in the parent screen you simply pass all the state in and you wire-up all the change callbacks
@Composable
fun UserProfileState() {
var username by remember { mutableStateOf("") }
var email by remember { mutableStateOf("") }
UserProfile(
username = username,
email = email,
onUsernameChange = { username = it },
onEmailChange = { email = it }
)
}
Or if you prefer it this way
@Composable
fun UserProfileState() {
val (username, setUsername) = remember { mutableStateOf("") }
val (email, setEmail) = remember { mutableStateOf("") }
UserProfile(
username = username,
email = email,
onUsernameChange = setUsername,
onEmailChange = setEmail
)
}