All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jsMain.com.zegreatrob.react.dataloader.DataLoader.kt Maven / Gradle / Ivy

There is a newer version: 5.6.6
Show newest version
package com.zegreatrob.react.dataloader

import com.zegreatrob.minreact.reactFunction
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import react.*

typealias DataLoadFunc = suspend (DataLoaderTools) -> D

@Deprecated(
    replaceWith = ReplaceWith("DataLoaderProps"),
    level = DeprecationLevel.WARNING,
    message = "Name to be removed."
)
typealias DataLoadWrapperProps = DataLoaderProps

data class DataLoaderProps(
    val getDataAsync: DataLoadFunc,
    val errorData: (Throwable) -> D,
    val scope: CoroutineScope? = null,
    val children: RBuilder.(value: DataLoadState) -> Unit
) : Props


private val cachedComponent = reactFunction> { props ->
    val (getDataAsync, errorData, injectedScope) = props
    val (state, setState) = useState> { EmptyState() }
    val scope = injectedScope ?: useScope("Data load")

    if (state is EmptyState) {
        startPendingJob(scope, setState, getDataAsync, errorData)
    }

    props.children(this, state)
}

fun  dataLoader() = cachedComponent.unsafeCast>>()

fun  RBuilder.dataLoader(
    getDataAsync: DataLoadFunc,
    errorData: (Throwable) -> D,
    scope: CoroutineScope? = null,
    children: RBuilder.(DataLoadState) -> Unit = {}
) = child(dataLoader(), DataLoaderProps(getDataAsync, errorData, scope, children)) {}

private fun  startPendingJob(
    scope: CoroutineScope,
    setState: StateSetter>,
    getDataAsync: DataLoadFunc,
    errorData: (Throwable) -> D
) {
    val setEmpty = setState.empty()
    val setPending = setState.pending()
    val setResolved = setState.resolved()
    val tools = DataLoaderTools(scope, setEmpty)
    setPending(
        scope.launch { getDataAsync(tools).let(setResolved) }
            .also { job -> job.errorOnJobFailure(setResolved, errorData) }
    )
}

private fun  Job.errorOnJobFailure(setResolved: (D) -> Unit, errorResult: (Throwable) -> D) =
    invokeOnCompletion { cause -> if (cause != null) setResolved(errorResult(cause)) }

private fun  StateSetter>.empty(): () -> Unit = {
    this(
        EmptyState()
    )
}

private fun  StateSetter>.pending(): (Job) -> Unit = {
    this(
        PendingState()
    )
}

private fun  StateSetter>.resolved(): (D) -> Unit = {
    this(
        ResolvedState(it)
    )
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy