0
0
Android Kotlinmobile~20 mins

State hoisting pattern in Android Kotlin - Mini App: Build & Ship

Choose your learning style9 modes available
Build: NameInputScreen
A simple screen where the user can enter their name. The text input state is managed outside the input composable using state hoisting pattern.
Target UI
-------------------------
| Enter your name:      |
| [               ]     |
|                       |
| [Submit]              |
-------------------------
Create a composable function that displays a TextField and a Button.
The TextField's text state should be passed in and updated via parameters (state hoisting).
The parent composable should hold the state of the text input.
When the user taps Submit, show a Toast with the entered name.
Starter Code
Android Kotlin
import android.widget.Toast
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp

@Composable
fun NameInputScreen() {
    // TODO: Hold the text state here

    Column(modifier = Modifier.padding(16.dp)) {
        // TODO: Call NameInput with state and onValueChange
        // TODO: Handle Submit button click to show Toast
    }
}

@Composable
fun NameInput(name: String, onNameChange: (String) -> Unit, onSubmit: () -> Unit) {
    Column {
        TextField(
            value = name,
            onValueChange = onNameChange,
            label = { Text("Enter your name") }
        )
        Button(onClick = onSubmit, modifier = Modifier.padding(top = 8.dp)) {
            Text("Submit")
        }
    }
}
Task 1
Task 2
Task 3
Solution
Android Kotlin
import android.widget.Toast
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp

@Composable
fun NameInputScreen() {
    val context = LocalContext.current
    val nameState = remember { mutableStateOf("") }

    Column(modifier = Modifier.padding(16.dp)) {
        NameInput(
            name = nameState.value,
            onNameChange = { newName -> nameState.value = newName },
            onSubmit = {
                Toast.makeText(context, "Hello, ${nameState.value}!", Toast.LENGTH_SHORT).show()
            }
        )
    }
}

@Composable
fun NameInput(name: String, onNameChange: (String) -> Unit, onSubmit: () -> Unit) {
    Column {
        TextField(
            value = name,
            onValueChange = onNameChange,
            label = { Text("Enter your name") }
        )
        Button(onClick = onSubmit, modifier = Modifier.padding(top = 8.dp)) {
            Text("Submit")
        }
    }
}

This example uses the state hoisting pattern by keeping the nameState in the NameInputScreen composable. The NameInput composable receives the current name and a function to update it as parameters. This way, NameInput is stateless and reusable.

When the user types, onNameChange updates the state in the parent. When the user taps Submit, a Toast shows the entered name using the current state.

This pattern helps separate UI from state management, making the code easier to test and maintain.

Final Result
Completed Screen
-------------------------
| Enter your name:      |
| [John Doe       ]     |
|                       |
| [Submit]              |
-------------------------
User types text in the input field, the text updates immediately.
User taps Submit button, a Toast appears saying 'Hello, John Doe!' (or the entered name).
Stretch Goal
Add a clear button inside the TextField to clear the input text.
💡 Hint
Use the trailingIcon parameter of TextField to add an IconButton that calls onNameChange("") when clicked.