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.DataProps
import com.zegreatrob.minreact.TMFC
import com.zegreatrob.minreact.tmFC
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import react.ChildrenBuilder
import react.StateSetter
import react.useState

typealias DataLoadFunc = suspend (DataLoaderTools) -> D

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

data class DataLoader(
    val getDataAsync: DataLoadFunc,
    val errorData: (Throwable) -> D,
    val scope: CoroutineScope? = null,
    val children: ChildrenBuilder.(value: DataLoadState) -> Unit
) : DataProps> {
    override val component = cachedComponent.unsafeCast>>()
}

private val cachedComponent = tmFC> { 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>>()

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