Closed lilactown closed 5 years ago
Will take a longer look soon, but after a quick glance, one thing that bothers (if I can say so) is the =
check. Are you assuming that the value is a js object or a CLJ data structure? I'm saying this because I've been bitten by a similar thing in Citrus, where we had a long vector of nested maps coming from the backend and only the last item was different, so this =
was taking a lot of time and blocking the UI. Should it be better to leave the check out by default and let React do its check (I know the rules documented somewhere), and offer an option to actually do the check?
I haven't looked at the other changes yet in the PR.
Perhaps you're right. We have an issue over at https://github.com/facebook/react/issues/15154 where we're trying to figure out if there's some extra optimizations we can do w.r.t. state updates.
I think that in practice, the chance that a state operation returns a structurally equivalent but referentially different value is rare. So might be good to keep the hot path clear of that.
I've always thought that the user should be able to supply their own comparison function, because they're best positioned to know what kind of data structures they use on a case-by-case basis.
So I think an API could look like so:
[foo set-foo] (<-state 0) ;; fall back to whatever React is doing with Object.is
[foo set-foo] (<-state :foo keyword-identical?) ;; only going to use keywords
[foo set-foo] (<-state {:some "thing"} =) ;; small maps with big ramifications
[foo set-foo] (<-state {:some "thing"} identical?) ;; big maps, prefer to re-render
(the last case could be omitted as identical?
is just ===
).
I would go further and provide nothing. The user can just do the custom comparison him/herself before calling set-foo
(this is what we ended up doing in our case). The good thing with this solution is that this code doesn't even have to be in hx
at all, easy to do outside.
I think that you will want to be able to do the quality check in the state computation, so that you can accommodate state changes occurring between when you call set-foo
and when the computation you dispatched actually occurs. This can't happen now, but will in Concurrent mode.
Another option for users is to use <-reducer
instead, like the React team has suggested for most non-toy situations.
This MR removes the Atomified wrapper returned by
<-state
. It implements a couple of new features:<-state
returns a tuple[state set-state]
set-state
will prevent re-renders triggered by structurally equivalent state objectsset-state
can be used with multiple arguments likeswap!
:(set-state assoc :new-key "new-value")
<-value
hook that can be used to optimize<-effect
,<-memo
, etc.