Fork me on GitHub
#fulcro
<
2021-09-24
>
Hukka08:09:44

Finally starting to use Fulcro seriously, not just testing it and getting to know it. And with that sensible architecture becomes more important, but I'm still struggling a bit with the graph based state management. I have a demo app, where I can create multiple origin-destination city pairs that the user can select. For now I have a model "Leg" that has id, origin, and destination. So far so good. Then I refactored the city selector to a separate component. Should I A) pass the id of the leg, and if it's the destination/origin to the selector, so it can mutate the Leg data when user makes a selection, or B) pass an onChange function from the Leg component, that knows where the mutation goes, or C) normalize the city, so that the Leg just links to two cities, and the CitySelector just gets the usual fulcro ident and can mutate that. C seem kinda heavy for single text field, but I wonder if in the long run it is simpler to normalize to maximum depth.

Hukka08:09:30

I could see more choices coming up with solution C. For example after I add a new text field to the Leg, say "Description", should I then be adding description idents? Or instead should both cities and descriptions be more generic "text" or "choice" objects in the same table (as long as they don't have a meaning outside the Leg component, so that I would for example need all chosen cities somewhere else)

Hukka09:09:00

If I were working on React or re-frame, I think I wouldn't even think of any other option than B, passing onChange handlers

Hukka09:09:23

I also haven't really read and watched through all the material available. Just started to feel like it's time to stop passively ingesting information and start using it too. But if there's a particular resource I should be reading to understand this kind of architectural decisions in fulcro, I sure can just go and read/watch that too!

tony.kay11:09:40

I do not normalize single fields. onChange is reasonable and what I mostly do. You can also use placeholders in pathom to fan out a query while using the same indent on a nested component. That is not really an option in GQL, but it is trivial with Fulcro and Pathom. Two components with the same Ident that have a parent child relationship can be quite handy in some cases.

Hukka12:09:38

Thanks. Have to read what placeholders and fan outs are, not there yet

Hukka12:09:20

Ok, read the pathom doc on placeholders. That was good to know, although I'm still at level where I don't use the remotes at all (tried the frontend mock pathom, and removed it after testing since I don't need it yet)

Jakub Holý (HolyJak)13:09:45

You do not really want the CitySelector to mutate a city, cities are immutable 🙂 You want it to change a Leg, namely the city at one its end. To me, an onChange handler passed from Leg to the Selector via computed props seems the simplest solution. (And the Leg can do m/set-field! in it)

Hukka14:09:44

> You do not really want the CitySelector to mutate a city, cities are immutable Heh, you got me

Hukka14:09:54

I actually earlier did have a more complicated model for a city. Populations etc., just to play with pathom resolvers. But at this moment they city, or the pair of cities is more like an ident to the travel connection

Hukka14:09:06

But more accurately am I mutating the leg directly, or a cityselection object that is linked to the leg

Hukka14:09:49

In any case, I felt like going for the option B too, but good to have confirmation that I'm not just using fulcro like vanilla react

Hukka14:09:00

I guess I got carried away. Thinking about this, I already had a reasonable schema for the data, but was thinking if I should change it to fit the UI, instead of fitting the UI to the schema

tony.kay16:09:46

Make a solid data schema... Pathom and EQL give the power to shape things to the ui. Fanning out and flattening the graph to meet the ui isn't conflated with schema like it is in GQL.

tony.kay00:09:46

Selecting idents/normalization does have to do with your data model, but what a lot of people don't realize is that any number of components can share the exact same idents. So, technically, you could make every single field of a form a different component, and just fan out the query...gets rather tedious to do so, though, and it makes saving a bit more painful.

Hukka07:09:16

Yeah, and I think I will use that a bit as a kind of a union. So the data entity still has the same type and ident, but has various different fields based on some type field. Or perhaps that won't work in my case and I will end up with distinct idents

Hukka07:09:05

Concretely, every leg of a trip has origin and destination, but flights and trains have reserved seats, ferries don't

Hukka14:09:25

Does anyone else have fulcro and calva playing well together? Seems to me like a bunch of stuff is broken, like all the refactor commands like "extract to a new function"

Jakub Holý (HolyJak)14:09:43

Never tried to use refactoring commands there 🙂 Good luck!

Hukka15:09:31

Not having any luck 😞

sheluchin15:09:50

Is there a :lint-as that we can use for these https://github.com/fulcrologic/fulcro-spec/blob/develop/src/main/fulcro_spec/core.clj#L15 to make the linter happy?

Jakub Holý (HolyJak)18:09:33

A question for #clj-kondo, no?

sheluchin18:09:54

@U0522TWDA I'm not sure. It's a Fulcro thing, I just need to help the linter figure out what to do with it. I thought it would be more of a Fulcro question.

Björn Ebbinghaus19:09:48

What exactly is the problem? The linter you show no warning if you refer these symbols.

sheluchin19:09:39

Ah, totally my misunderstanding. Yes, that does fix my concern. I don't understand how tests can all run and pass without those symbols being referred.

Björn Ebbinghaus23:09:30

The symbols are just symbols without any namespace, they are declared just for linting.

Tyler Nisonoff17:09:43

Im having an issue where after a load, and a call to fs/add-form-config* , my entity is always dirty, due to an edge to a subform (to many) When i print out the dirty diff, I get something like this:

{[:parent/id  "aaa"]
   {:parent/children {:before [[:child/id  "abc"]
                               [:child/id  "def"]]
                      :after  [{:child/id  "abc"
                                :child/other-attr "def"
                                ...
                                }]
It seems like the before just contains the idents, whereas the after block contains the same children, but the full props rather than just the idents Any idea what im doing wrong with form-state to cause this issue?

tony.kay17:09:27

Hey Tyler. You might take a look at the defsc-form code, since it sets this stuff up for you. Chances are you didn't put the "edge" in the fields set on the parent. The edges are "fields" on the parent, and then the child lists it;s fields as well. Look at the normalized data in your database. Each entity in your "form set" should have form configuration.

tony.kay17:09:20

The edges are fields because they can appear/disappear.

tony.kay18:09:47

Then make sure you do add form config to the parent and every child (if in a mutation), or against the entire tree before you merge it....and make sure form-config is in the query of all forms/subforms.

Tyler Nisonoff18:09:33

Thanks Tony, I’ll check that when I can

Tyler Nisonoff19:09:44

ah i think i figured it out — the child was in the query twice — once joined properly, and once on its own (like a non-ref attribute) made this mistake because the query is dynamically being built