Fork me on GitHub
#fulcro
<
2021-09-27
>
Jakub Holý (HolyJak)08:09:21

Hi Tony! I am looking into preventing the https://book.fulcrologic.com/#warn-uism-sm-not-in-state warning when I change-route in my app's init function. This is what I have now and it is broken:

(app/set-root! app Root {:initialize-state? true})
(dr/initialize! app) ; BEWARE: "async"!
(dr/change-route! app ["all"])
and that's because dr/initialize! is not immediate since it only submits a transaction. The obvious solution is to replace the direct call to change-route! with issuing a mutation that does the same. My question is: is that what you would do or is there a better way? But fulcro-rad-demo does just ☝️ So perhaps I should just ignore the warning?? Thank you!

tony.kay12:09:48

Yeah, it is a bit of a chicken-and-egg problem. I really should tune up the underlying code...I've really left no easy way for you to not get a warning on startup. Most likely the initialize! function should just be synchronous.

🙏 2
Hukka12:09:31

When should shared state be used instead of globally visible var (perhaps an atom)?

tony.kay13:09:52

Great question. It has a relatively narrow use-case that is also solved by React Context: having something from "above" that you don't have to explicitly query for that, when it changes, causes a refresh. I use shared props in the i18n lib to share the current translations and locale. If those change, then everything needs to refresh. That's about the only place I ever use it TBH. Another potential place is for things like auth/current user session info. I typically prefer having the explicit join in my query to the data I want...fewer places to go looking for it. But for i18n having to add [::i18n/current-translations '_] to every component (including those that would otherwise not have a query) is ridiculous....using an atom is tractable as well, but it requires that you remember to force a global root render whenever you change that atom (which you can do with a watch) so it's all up to your preferences really.

tony.kay13:09:53

In some ways the atom-with-a-watch is superior, other than installing the watch on hot reloads needs some attention to detail...but updating that global state is less opaque. Shared was part of the original Om Next library, and I've mainly carried it along "because it was there"

Hukka13:09:45

React Contexts can be defined at arbitrary depth, and shadowed, but based on the docs I understood that shared state is strictly defined at root level. Did I understand correctly?

✔️ 1
Hukka13:09:35

I could definitely see a use for react tree scoped/bound "globals", in addition to lexically scoped globals

Hukka13:09:39

If not elsewhere, at least in a component showcase/test page, where you'd perhaps want to have all kinds of versions visible side by side, while normally they would follow some global flag

Hukka13:09:30

Being global with a big G was one of the intractable obstacles I often found with reagent and re-frame

tony.kay19:09:47

So, some things are just naturally global: The current translations/locale. The current user/session. The current URL. The current UI route. But, most things are not, and I agree that shared is not sufficient or appropriate for that. React Context didn't exist when it was created. You can definitely use React context, and it is the scoped facility for this kind of thing in React. I do not implement something like it, because it is already there. Ideally we'd be able to use dynamic vars, which is the Clojure solution to this kind of thing...but unfortunately the rendering is an async kind of thing where scoped clj bindings are not in effect when you think they are.

tony.kay19:09:18

That said, I would not object to a reasonable wrapper around it (React Context) that made it appear more natural, even though it is pure React/js

Hukka07:09:02

Yeah, indeed the language provided mechanisms can't work when react does it's thing however it wants to. I'll see how the current hooks support is done to see how I could access the useContext hook

Hukka07:09:05

Ah, I see. I can just call js/React and everything it provides as if I was in the usual render function

Hukka07:09:54

Heh, and there was the use-context already, just wasn't mentioned in the book

Hukka07:09:01

And even the doc string for update-shared! mentions that I should consider contexts instead of shared state

Hukka07:09:28

Very likely I would just use functional components so I can access multiple contexts, but just to understand things: is there a way to use react contexts with class based fulcro components? I.e. how can I set the contextType and access this.context?

tony.kay15:09:35

Fulcro components are React components. this is the React this

Hukka18:09:29

Ah, somehow missed this crucial thing. Thanks

tony.kay19:09:49

Fulcro piggy-backs the CLJS props as fulcro$value in the react props...so if you look at (.-props this) you'll see that. This is just so we don't have to deal with low-level js values all the time.