Fork me on GitHub

Can the new component registry replace actors whose sole purpose is to provide class information?


@levitanong That’s one goal…the internals currently use metadata to track that. I still think the aliasing of them is useful for SM reuse, but in cases where reuse isn’t likely you can certainly just use the classes via whatever.

👍 4

There was once a post linking to detailed notes on significant redesign of fulcro internals. An RFC-like document. Can someone please link me to that.


My limited search-fu didn't yield anything.


@jaihindhreddy I’m still working on those, but the originals are somewhat out of date. The transaction processing one was too complicated…but anyway, they’re in a really obscure place:


There is nothing in those that is a commitment…they are more a way for me to think through existing issues and look for good solutions. The transaction semantics one is not going to be much like the current version of the doc…I’ve got a clearer set of ideas now.


Thank you sir! For the link, and the explanation.


I’m fetching some updated data on a form field change, when I update the state it doesn’t seem to be refreshing in the form. Its like one step behind, it’ll update but only until the previous value. I’m using the edit-existing- mutation flow that the docs recommend, but something is still off. Any ideas?


I tried using the :refresh [f/form-root-key] as well, but that seems to refresh the values to their initial state


@pvillegas12 The problem you were having within inputs last week: was that happening when you were “pushing” data into form fields? There is a bug in the wrapped DOM inputs that will cause that…I just ran into it myself.


@njj might be same for you


I’m not so sure, in my case I’m getting the update one behind. So I type a field, get an update - nothing changes, I type in field, change shows previous calculation. If that makes sense…?


My workaround was making two mutations that re-render the component to force the refresh @tony.kay


Yeah…wrapped inputs are painful


I’m trying to figure out a fix


@pvillegas12 have any example of what that looks like?


The solution I did was do (prim/transact! this [(mut-a ...) (mut-b ...)]) which forces the input component to render twice


Still trying to get my head around normalization <-> remote. I was expecting (prn (om/tree->db [{:join/test [[:foo '_]]}] {:join/test {:foo "bar"}})) to print {:foo "bar"} because it would see the ident. Why am I wrong?


I assume it could just as well be prim/tree->db


But taking the example from the docs with ^ metadata {:component Person}. What if the query also contained a link [:foo '_]? Does it still try and put that result under the Person ident?


@danielstockton I don’t know exactly how Fulcro would handle a link query from the remote, but the bigger issue is there is no reason to do that. In Fulcro, loading remote data is completely separate from querying locally (unlike Om Next). Just create a separate set of query-only components to shape the data you request in your remote loads. Once that’s loaded and normalized, your UI components can utilize that same data, just make sure you use the same idents when necessary in the UI components. And if you need to add artificial joins, additional UI state, etc. that’s ok too, because that will never get sent to the server. Not sure if that makes sense - it’s one of those concepts that’s so clear once you “get it”, but can be hard to articulate concisely. If it’s still unclear, ask and I’ll try to clarify.


It makes sense, although the idea of two queries for load and hydrate seems a bit strange. It still doesn't really help me understand how tree->db functions.


Is there a good way to convert general idents from datomic {:db/id ... :db/ident :my-ident} to simply :my-ident when using queries with fulcro?


I usually just have some post-processing (I assume you’re talking about in pulls) that “raises” them…via clojure.walk or specter


What Tony said. Except sometimes, I’ve found it useful to attach additional metadata to the enum types, so in that case I just model them as a separate normalized entity and join them in the query.


I feel like without really understanding the fundamentals, I can't really decide on the optimum structure for my data.


I'm trying to establish a pattern that removes as much thought as possible from the process. Perhaps giving each component an ident such as [:components/by-name :header] and then it can have properties like :header/title that live in it's own table, but also :header/links [[:links/by-id 1] [:links/by-id 2]] that link to other tables.


That’s the idea. Just about every component has an ident, and if fact if you have a component without an ident and query, you could just as easily convert it to a pure function. I find I usually have 3 types of components - the query components for loading data, UI components representing the same entities, and then the components that lay out everything. Often, you can combine the first 2, so you don’t have that dreaded duplication, but that’s not always the case. For example, sometimes I load more data from the server than immediately needed, so I don’t have to make another round trip later, but parts of the UI may only be showing a subset of that data. In that case, the separate loading components help.


I suppose that's a good point. Not necessarily loading data in advance, but you might have two queries which need different attributes of :people and so you need one query that merges all those attributes.


It still seems feasible to automatically merge the two queries into one to the remote, and keep things DRY.


That, or go the other way - grab the query from the server query component, and then modify it (if needed) in the UI component. I treat those server query components as the source of truth about the data model (I actually put them all in a single namespace called 'model'). I also have ident generating functions for each entity in that namespace, which are used for generating idents in whatever components use that entity type. You could probably do the same thing with the queries - move them out to a 'base query' definition (which is just a vector) and then reference it (and modify if needed) from each component needing that query.


Note I haven't done that yet (separating the queries), but have thought about it. In theory it should work, just have to weigh against the tradeoffs. In particular, I like seeing the explicit query in my UI components, so the tradeoff is duplication of the query vs. obfuscating what's being queried for when you typically need it most (i.e. using the data in the UI).


Interesting, I was pondering something similar to the 'base query' idea and auto generating idents


The fact I can make things work with two queries seems like a hack, when the original query should be information enough to be able to normalize it. It's actually just the kind of thing I feel like I would resort to, because I lack a basic understanding of queries, components, identity, normalization..


"If the metadata was missing then it would assume the person data did not need normalization." makes sense when you've written flat attributes that actually live in a table somewhere. However, in the case of a link, it should know that it belongs at root without metadata, shouldn't it?


@njj @pvillegas12 Found it. The wrapped inputs screw up if you send a non-string as an input value…e.g. Number 2 instead of “2”


All HTML inputs use strings internally, so when the logic tries to detect the async change it pulls the value from the real DOM input (which is always a string, even when using HTML5 date or number inputs) and looks at what is coming in from props. I’m adding a warning to the DOM ns, since that prevents any existing app breakage. The fix is simple: make sure your :value on low-level inputs is forced to string.


That didn’t seem to fix my situation, not sure if you have time but this is the gist of it,


Basically my updates from the app-state are one behind


or so it seems…


you do realize that set-string! is not an “immediate” thing, right? I.e. your props of the component are immutable


so if you send them to a mutation, they will be the stale version


So at a glance, it looks to me like you’re sending an old version of your props to the mutation, assuming that somehow set-string! will have changed them.


but that glance might be too brief…


you’re saying that the input’s appearance doesn’t change…but if you log the props that are coming to it: is that because it didn’t get refreshed (no log message), got refreshed with the wrong value, or the input itself ignored the correct value?


only the last one would be fixed by my suggestion


the inputs appearance changes but the values I get back from the server are behind by one mutation


maybe I should print out the form value i’m sending over to ensure it’s the same as what I see in the ui


That was it @tony.kay doh!


So.. how can I wait until the form is updated to have the correct values?


I guess I can always just have a mutation that accepts the event value, since that will be the correct value


Actually that wasn’t it, I’m passing the fresh data now and the UI still isn’t updating. I was able to get it working by having the API call on both on change and on blur


Which seems odd, but I guess whatever works at this point


ok I’ll give that a shot


so basically :value (str value)


I could also force it internally, but I have no idea what that might break for ppl…I suspect nothing, but a warning is better than a change.


2.8.9 on clojars: Fixes form-state to be usable in React Native @mdhaney, and adds a console warning in dev mode to inputs whose incoming :value does not match the prior value in type, which is the source of “missed pushed updates”.

👍 16

ooops…I think I forgot an import 😕


that looks like a bad release


2.8.10 pushed to clojars