What’s the bundle size of DataScript? Loading time?
https://git.sr.ht/~severeoverfl0w/hxadapound I spent the morning assembling this. It's helix, hicada and an atom for a "db". I haven't written "connect" yet, but I think that's the next step. I'm not sure if the use-store hook really makes sense if I am targetting a connect-based workflow. I've inlined a "last rendered" on every component, so that it's clear how it's responding to the state.
I find the hiccup / fn call mix confusing :)
Does it make sense to use context if db is already a global?
I guess I’d either go full global, or route everything through context (including the ref to db)
I need to patch hicada to transform [foo] to what I mean. I want to go full hiccup. Although, the current way looks far more like hiccup. It just doesn't look like reagent.
I want to go fully context, I just haven't figured out the details yet.
Advice on how to do that is welcome. I didn't like the setter/getter method tbh.
I’m just reading through https://react-redux.js.org/api/hooks
I wonder if there’s any real downside in wrapping redux
At the bottom of that doc page they refer to this https://blog.isquaredsoftware.com/2019/07/blogged-answers-thoughts-on-hooks/
And https://twitter.com/acemarke/status/1056669495354421249?s=20
Redux is much easier to access now, it's not a terrible idea. I'm holding off right now, because I'm not sure if I want to dispatch events or not.
I'm going to read those links... after I install an alternative slack client. I have a short screen and can barely read 5 lines at a time in slack 😠 . Sorry OT, but frustrated.
That whole blog has some interesting links, see also https://blog.isquaredsoftware.com/2020/01/blogged-answers-react-redux-and-context-behavior/ and https://blog.isquaredsoftware.com/2020/02/blogged-answers-why-redux-toolkit-uses-thunks-for-async-logic/
https://github.com/aaronc/freactive.core this is probably pretty useful too :) There's a lot of value in working on atoms and allowing something else to manage the lenses on top of that.
Note when you’re trying to mix atoms and react: https://github.com/Lokeh/hx/issues/41
Isn't that more about backing react state with atoms?
I think the concurrent mode concerns can be solved with the new hook designed for external state purposes.
I've got a very basic connect api up & running for hxadapound now. So you can call connect on a component. It has the exact same API as redux's. Here's an example for the common counter:
(defnc counter*
[{:keys [count increment decrement]}]
[:<>
(last-render)
[:span (str "Count: " (or count 0))]
[:button {:type "button" :onClick increment}
"+"]
[:button {:type "button" :onClick decrement}
"-"]])
(def counter
(connect counter*
#(hash-map :count (:count %))
(fn [db]
{:increment #(swap! db update :count (fnil inc 0))
:decrement #(swap! db update :count (fnil dec 0))})))
Note that there's no longer any global store access & counter* is a pure component, very friendly to previewing in a devcards thing, even if you wanted to play with state.
https://github.com/tatut/koukku heh, new wrapper!
I like it :) It has a compile-time hiccup with support for a few common elements (for, when, if) in the form of custom keywords. I suppose that does mean it's not suited to wrapping around the whole body?
regarding koukku, I wanted to do as much at compile time and have the code yield actual react/createElement
calls so the runtime layer is very minimal
that means there's some restrictions, like all components having to wrap their markup in the html
macro and can't just return a hiccup vector
as there's no runtime implementation of hiccup in the library
Same goal as hicada :) Compile-time hiccup is an interesting goal really
I actually converted one of my small reagent+tuck apps to use koukku and it was surprisingly straightforward, the runtime restriction wasn't a big deal
and the react/useReducer works very well.. just have a multimethod as the reducer, but you do need to pass the dispatch function via some magic, because passing along the fn as props to all children makes them all rerender all the time
You can probably pass the dispatch function by using useCallback
(unless it has dynamic deps)
I wanted to refrain from too much magic in the html generating macro, so it won't recurse into user clojure code and rewrite if branches or for body... that's why the common control flow convenience elements are provided
btw, there's a usage example in the repo https://twitter.com/tatut/status/1254323608240914432 using mui
I think it's nice that the JS React world is coming to functional components as well, I guess there will be lots of stuff in this space
I think I'll try the useCallback, I missed that the first time around
no, actually my [some-fn ...args..]
form is creating new functions every time, so need to memoize that
seems the dispatch fn returned by useReducer has stable identity
Putting it in context means you can mock it or use multiple global values throughout the tree
Yeah, I followed up on the next message :) important to keep the whole thing in the context, and don’t use any global references - or forego context entirely!
yes, this is documented explicitly in the react docs
Redux's value-add to the world was really in creating a lightweight store abstraction (immutable, notify all subscriptions on change) and then tying it alongside middleware. We could try and integrate with them, but I think the downsides would be: - We'd probably want to invent a way for events to be cljs maps, so basically the use of clj->js as a middleware (not particularly suitable for typing/clicking events due to performance) - middleware makes this possible - We'd not benefit from most of the reducer libraries that exist, if we want to utilize cljs data structures to be our store (I strongly think we should) here's an example of a library which manages to support immutable.js, notice how it uses an alternative entry point to provide specific support https://github.com/supasate/connected-react-router/blob/master/FAQ.md#how-to-support-immutablejs - We could utilize some side effect libs, I picked https://github.com/zslucky/redux-fetch-middleware at random. But it immediately feels like I'm not buying a lot of value, it looks very similar to things like https://github.com/Day8/re-frame-http-fx I don't think we get a lot of the benefit that we would enjoy. React-redux is not massive, 1k loc non-whitespace lines. I think we can capture the core of redux ourselves, without needing to rely on redux directly - which I'm pretty sure duplicates a lot of cljs/gcc core.
there are many other similar libs like redux (and alternatives like mobx or rxjs) that favoring redux over them would make the objective more about redux than about react
FWIW I still think that Redux, like re-frame, is the wrong abstraction. I would like to focus more on building abstractions over domains, rather than super broad things like "global state management." If we think something like redux/re-frame can be used to build higher-level abstractions over those domains, then I see value in them. but IME with both redux and re-frame, the abstraction always seems to stop at the point of redux and some middleware, or re-frame and some effects
e.g. if we can ideate an amazing interface for fetching/caching/subscribing to remove data, and it falls out that Redux (or some CLJS equivalent) provides good building blocks for that, then I think it's valuable
similarly, a great API for a concurrent mode client-side routing solution might use a global event emitter like Redux, or it might not.
trying to leverage a monolithic global state management solution IME ends up being a lowest-common-denominator API that feels difficult to boil away. it's telling that a lot of high level libs that started out building on top of redux, are either fairly unpopular or eventually removed redux because it was too opinionated for consumers
I 100% agree, but I am taking soo many contrarian positions on this slack that this was a battle I didn't really want to join 🙂 Glad that there are others who think similarly!
I like the idea of single source of truth, but I have this suspicion that people misunderstand it. The single source is not about ALL state in an app, but ANY state. Which means that different parts of the state might have different single sources. In fact, it's much more easy to dismantle highly derived state if one takes this approach because now the logic that manages said state can take this role, instead of having actions/effects tied to components or apps. It can even move outside.
@lilactown are you thinking of things like a data synchronization library?
depends on what you mean by > data synchronization
I guess the act of fetching data, and sending changes back to somewhere else. Everything in the range of datahike, firebase, or REST calls based on a schema.
I can't wrap my head around the problem of an e2e solution like datahike/firebase yet, but something on the level of: • fetching data • suspending based on query • optimistic updates on mutation are what are top of my mind lately
What is "suspending based on query"?
Some of what you're describing reminds me of dnolen's work on om.next
if you look at react's page on data fetching with suspense
they sort of develop a pattern: • an action starts a request (e.g. navigation, button press, etc.) • a related render is triggered, which reads from the cache and suspends • when request has completed, re-render with data this makes sense when you think of it in the scope of a single request. but often, the apps that I've built are fetching and populating different pieces of domain info (e.g. a particular user's information) ad-hoc
so when I'm developing a component, what I would like to do is subscribe to the domain info I need, and define the behavior which should suspend the component, irrespective of the exact request that ends up triggering that behavior or updating that domain info
if that makes any sense 😛
And I am just simply suspicious of this idea that the render, that is the View should trigger some IO. The view/component depends on the data, declaratively, not the other way around
I agree. the pattern I'm describing would encourage you to separate fetch from render, instead render queries the cache and decides whether to suspend until data is ready
Often, the app looks/design/content changes at the same time the API changes, if the renders need to handle both, the complexities get entangled. With separated fetch (I like to call these services, like ServiceWorker) the two can be maintained entirely separately. This is why I want to use the same query language internally as externally, but often backend developers are not very enthusiastic about adopting datalog or even transit 🙂