Error: "@Composable invocations can only happen from the context of a @Composable function"

90.7k views Asked by At

I'm trying to show a toast message when clicking on a toolbar action, but I got this error

@composable invocations can only happen from the context of a @composable function

Code:

@Composable
fun Toolbar() {
    TopAppBar(title = { Text(text = "Jetpack Compose") }, navigationIcon = {
        IconButton(onClick = {}) {
            Icon(Icons.Filled.Menu)
        }
    }, actions = {
        IconButton(onClick = {
            showMessage(message = "test")
        }) {
            Icon(vectorResource(id = R.drawable.ic_baseline_save_24))
        }
    })
}

@Preview
@Composable
fun ToolbarPreview(){
    Toolbar()
}

@Composable
fun showMessage(message:String){
    Toast.makeText(ContextAmbient.current, message, Toast.LENGTH_SHORT).show()
}
5

There are 5 answers

7
Gabriele Mariotti On BEST ANSWER

The onClick parameter doesn't accept a composable function. Remove the @Composable annotation in the showMessage.
Use something like:

@Composable
fun Toolbar() {

    val context = LocalContext.current

    TopAppBar(title = {},
            actions = {
        IconButton(onClick = {
            showMessage(context, message = "test")
        }){}
    })
}

fun showMessage(context: Context, message:String){
    Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
0
gustavoknz On

I got the same error and my solution was adding a @Composable annotation to the parameter in my method where I pass another composable function.

Example:

fun drawScreen(navigationIcon: @Composable () -> Unit) {
    navigationIcon()
    ...
}
0
BaBaX Ra On

You mean something like this?

@Composable
fun MyTopAppBar(
        title: String,
        actionItem: TopBarActionItem,
        navigationClick: (@Composable () -> Unit)? = null) {}

And how do you invoke navigationClick? The invoke() method itself is not composable and got the error again.

You can't use navigationClick?.invoke()

1
Bharat Lalwani On

Here onClick() doesn't need any Composable function that's why it is throwing an error. Just remove @Composable from the showMessage function.

0
Kishore Jethava On

If someone wants to use Composable on click event

Column {
    var isClicked by mutableStateOf(false)

    Button(onClick = { isClicked = true }) { Text(text = "Click Me") }

    if (isClicked) {
        isClicked = false
        // display your composable
    }
}