News for hackers. Stuff that matters.
Re:Solid.js feels like what I always wanted React to be by jillesvangurp on Tuesday March 01, 2022 @01:56AM (#30510560)
I think for progress you need to look outside the js world. Fundamentally, people keep repeating the same mistakes there.

I'm having a lot of fun lately using Kotlin-js for example. We use the Fritz2 framework, koin for dependency injection (popular on Android as well for good reasons), and fritz2 relies on kotlin's co-routines and StateFlow for state management. It makes for a surprisingly concise code base. For example, the counter example from the article with that would look something like this:

  class CounterStore : RootStore<Int>(0) {
    val koinCtx by lazy { GlobalContext.get() }

    // handler that you can bind events to or invoke directly like below
    val inc = handle { old -> old + 1 }

    init {
        // launch co-routine to keep on incrementing the counter
        GlobalScope.launch {
            while (true) {
                inc()
                delay(1000)
            }
        }
    }
  }

  val koinCtx by lazy { GlobalContext.get() }

  fun RenderContext.counterComponent() {
    val counter by koinCtx.inject<CounterStore>()
    h1 { +"A Counter" }
    // react to changes in the counter
    counter.data.render { currentCount ->
        p {
            +"Current count: $currentCount"
        }
    }
    pushButton { 
        icon { arrowUp }
        events {
           clicks handledBy counter.inc
        }
    }
  }

  fun main() {
    startKoin {
        modules(
            module {
                single {
                    CounterStore()
                }
            })
    }
    render("#target") {
        counterComponent()
    }
  }
There's a lot going on here that I can't explain here. But having co-routines means having a proper reactive framework that you use to react to events and update stores, which is where you keep your state. counter.data is a so-called StateFlow; the render function maps updates in that flow to the dom. In the example I have both a button and a co-routine updating the store via a handler lambda function.

Using koin here, just means keeping glue code out of places where it doesn't belong. It's technically optional but makes a lot of sense in larger applications. Because components are extension functions on RenderContext, I use a global variable to get to the koin context. That allows me to inject my dependencies into components with a minimum of fuss. Where Fritz2 gets fun is with more complex state using data classes, lenses, validators, routers and a few other things. And they also take care of styled components and they even have a nice component framework that you can use. Not for everyone and there's a bit of overhead in terms of download size. But great if that less of a concern.

Re:Solid.js feels like what I always wanted React to be by mst on Tuesday March 01, 2022 @01:26PM (#30517902)
The way mobx-state-tree uses generators as a coroutine-like affordance is worthy of study.

I would not at all be surprised or troubled if, having studied it, you still dislike it, but there are definitely ideas in there that I consider to be at worst -interesting-.

Re:Solid.js feels like what I always wanted React to be by ohgodplsno on Tuesday March 01, 2022 @02:54AM (#30510975)
>GlobalScope.launch { ... }

I can't begin to express how sad that makes me. Your component should have its own scope that it destroys when it gets destroyed, otherwise your coroutine leaks to the outside world when your component is gone from view.

Re:Solid.js feels like what I always wanted React to be by jillesvangurp on Tuesday March 01, 2022 @07:02AM (#30513101)
Sure, but I wasn't going to fit a whole lot of boiler plate in a comment on HN to do that. Using Globalscope in a demo is perfectly valid; a lot of co-routine presentations do that as well. Normally, I'd use some named scope and life cycles associated with e.g. koin modules or a web worker. This is just something that I quickly knocked out that actually works. Also, this is not Android. There are not a whole lot of life cycle events beyond "page loaded".