helix

https://github.com/Lokeh/helix
orestis 2020-03-09T07:36:37.148100Z

Seems like @mhuebert is also attacking this problem of global state / concurrent mode. Happy that I found this comment as I was ready to go and do my own thing. Seems like if the core team is dealing with this, we can go about having global state in concurrent mode without much hassle.

orestis 2020-03-09T11:23:03.154Z

@mhuebert Is this something you are toying around or are you putting it to production use? I'm kicking the can down the read on a new project waiting for concurrent mode to at least get another release, but at some point I need to start coding, would like at least the state management to be locked down before we get too far...

2020-03-09T11:43:59.157200Z

@orestis ’tis a good question. I’ve set up a little backwards-compatibility layer so that I can already use the mutableSource API but can fall back to a non-concurrent-safe implementation (best NOT used with concurrent mode if you want to avoid tearing), based on useState and useLayoutEffect.

(ns triple.view.react.mutable-source
  (:refer-clojure :exclude [use])
  (:require ["react" :as react]
            [applied-science.js-interop :as j]))

(def ^:constant feature-enabled? (j/contains? react :createMutableSource))

(defn create [store get-version]
  (if feature-enabled?
    (react/createMutableSource store get-version)
    (j/obj :store store :get-version get-version)))

(defn use [source get-snapshot subscribe]
  (if feature-enabled?
    (react/useMutableSource source get-snapshot subscribe)
    (j/let [^:js {:keys [store]} source
            ^:js [value set-value] (react/useState #(get-snapshot store))]
      (react/useLayoutEffect #(subscribe store (fn [] (set-value (get-snapshot store))))
                             #js[get-snapshot])
      value)))

2020-03-09T11:44:37.157500Z

^the above is by no means battle-tested

2020-03-09T11:44:57.158Z

however in principle there is no reason why this, or some variant of it, can’t work

2020-03-09T11:45:23.158600Z

so long as limitations are accepted (ie. we actually do need React’s mutableSource implementation to “safely” rely on external state in concurrent mode, can’t fake that with use of existing hooks)

orestis 2020-03-09T13:07:12.160300Z

Cool, I guess then the exercise becomes how to implement get-snapshot , get-version and subscribe -- I need to actually read the RFC to get the semantics.

lilactown 2020-03-09T17:56:11.160600Z

I’m curious how useMutableSource flows into Suspense

lilactown 2020-03-09T17:57:32.161400Z

one of the things i’ve been thinking about is how best to subscribe to a cache that leverages suspense

lilactown 2020-03-09T18:00:47.163200Z

the simple case where you start fetching data for a new screen you’re transitioning to seems easy. but when you have multiple components on the page that can suspend based on some fetch that isn’t necessarily re-rendering / re-mounting based on the action that initiates the fetch, you need some way of subscribing to the fact that someone has started fetching

lilactown 2020-03-09T18:01:24.163700Z

or, you might not want to suspend but you definitely don’t want to show stale data, so you need to re-render when new data has been fetched

lilactown 2020-03-09T18:06:04.164300Z

I think one idea would be to trigger a render from the root, but useMutableSource might be slightly more efficient

lilactown 2020-03-09T18:35:34.165300Z

re: using @ / reagent-style deref inside a component to subscribe, I think that ship has sailed. we should expect people to use a hook like use-atom rather than implicitly subscribe by dereference