# Debouncing Clicks in Compose

I recently needed to add a debouncing operator on my button clicks in a Compose multiplatform project. I thought I'd share my solution in case it was useful to someone else.

First, we define an `EventProcessor` interface. The concrete implementation will be responsible for debouncing our clicks.

```kotlin
internal interface EventProcessor {
    fun processEvent(event: () -> Unit)

    companion object {
        val buttonClickMap = mutableMapOf<String, EventProcessor>()
    }
}
```

The implementation:

```kotlin
private const val DEBOUNCE_TIME_MILLIS = 1000L

private class EventProcessorImpl : EventProcessor {
    private val now: Long
        // this is being used in Compose multiplatform 
        // switch out with whatever millisecond provider you want
        get() = Clock.System.now().toEpochMilliseconds()

    private var lastEventTimeMs: Long = 0

    override fun processEvent(event: () -> Unit) {
        if (now - lastEventTimeMs >= DEBOUNCE_TIME_MILLIS) {
            event.invoke()
        }
        lastEventTimeMs = now
    }
}
```

The `Composable` function where our `EventProcessor` will be used and a helper function for getting this button's `EventProcessor`

```kotlin
internal fun EventProcessor.Companion.get(id: String): EventProcessor {
    return buttonClickMap.getOrPut(
        id
    ) {
        EventProcessorImpl()
    }
}

@Composable
fun debouncedClick(
    id: String = randomUUID(),
    onClick: () -> Unit,
): () -> Unit {
    val multipleEventsCutter = remember { EventProcessor.get(id) }
    val newOnClick: () -> Unit = {
        multipleEventsCutter.processEvent { onClick() }
    }
    return newOnClick
}
```

Here is an example of it being used:

```kotlin
PrimaryButton(
    onClick = debouncedClick {
        // handle click
    },
) {
    Text("Button")
}
```

Full code:

[https://gist.github.com/j-roskopf/990baa5beef767fbb2fae8cce33e2529](https://gist.github.com/j-roskopf/990baa5beef767fbb2fae8cce33e2529)
