mirror of
https://github.com/jlengrand/compose-multiplatform.git
synced 2026-03-10 08:11:20 +00:00
How to use HTML based @Composable functions in JS?
Useful links:
- @Composable functions can't be invoked from JS directly (because every @Composable function has implicit parameters added by compiler plugin)
- We can wrap @Composable functions into some usual function (with @JsExport) which can be invoked in JS as is.
- Every call to a "wrapping" function will create a composition (part of DOM controlled by Compose runtime)
- It's important to
disposea composition when it's not needed. - The composition's state can be controlled by creating an arbitrary
Controllerclass, which implements and exposes necessary functions for state updates.
Simplified example (see full example in src/jsMain):
// Composables.kt
@JsExport
abstract class ComposeCounterAppController {
abstract fun setCount(newCount: Int)
abstract fun dispose()
}
@JsExport
fun ComposeCounterApp(rootId: String, onCountChange: (Int) -> Unit = {}): ComposeCounterAppController {
var count: Int by mutableStateOf(0)
val composition = renderComposable(rootElementId = rootId) {
// Counter is a @Composable function
// see full example in src/jsMain
Counter(count) {
count = it
onCountChange(count)
}
}
return object : ComposeCounterAppController() {
override fun setCount(newCount: Int) {
count = newCount
}
override fun dispose() {
composition.dispose()
}
}
}
Then in JS we can use ComposeCounterApp function:
// see src/jsMain/resources/use_compose.js file for a full example
counterController = MyComposables.ComposeCounterApp('counterByCompose', (newCount) => {
console.log(`Counter was updated. New value = ${newCount}`);
});
The module name was overridden to make it convenient for usage in JS:
// webpack.config.d/configModuleName.js
config.output = config.output || {};
config.output.library = "MyComposables";
Building and using the output
./gradlew jsBrowserProductionWebpack
This will produce the output in build/distributions.
Then we can use exported functions from web-compose-in-js.js (the filename is defined by the project/module name).
<script src="web-compose-in-js.js"></script>
<script src="use_compose.js"></script>