Fork me on GitHub
#re-frame
<
2023-01-23
>
scarytom12:01:43

I have a question about the relationship between the global re-frame app-db and component local state facilitated via reagent atoms. When designing a new component it makes sense for transient state scoped tightly to this component be held in a r/atom local to that component. This avoids polluting the app db and makes it easier to re-use that component. An example might be the current sort-order on table headings, or perhaps the intermediate state of an uncommitted form field. If we have a handful of components, say some specialist form fields, that interact with one another, it can be helpful to create a composite component for those fields and share some local state between them. This can extend to using local state for the form as a whole. My question is, when does it make sense to start leveraging the app db? I find that it makes sense to use the app db to store the results from API calls, rendering views on those data via subscriptions, but it makes less sense to pump form fields via the app-db, instead having form submission send local form state as an argument to the effect handler which makes the writing API call. Thoughts?

p-himik12:01:23

> when does it make sense to start leveraging the app db? When you consider a particular kind of data to be a part of your app's state. > This avoids polluting the app db What do you mean by "polluting"? > current sort-order on table headings > the intermediate state of an uncommitted form field I would 100% consider both of those to be a part of the application state. I would not consider a part of the state things like animation progress, derivative state, audio playback position, etc. > it makes less sense to pump form fields via the app-db Why?

hifumi12313:01:36

I'm using re-frame in a front-end and I've been finding it difficult to make re-usable components. I'm probably missing some obvious parametrization of my subscriptions and views, but for now I have reagent and re-frame components in their own namespaces, where the re-frame ones tend to represent the bulk of a page's state,, then the reagent components have local state and, if they are part of forms, use on-blur or a related prop to hold those values somewhere in the app-db so my effects can access the data users want to submit. Strong emphasis on "reusability". Another big thing I find difficult about using the app-db at all is cleaning up state once it's no longer needed. I find it very easy to leave junk in my app-db and clobber state when it is shared across pages

scarytom14:01:58

@U2FRKM4TW we battled for a while with issues caused by putting live edits of form fields straight into the app-db: 1) when a user typed in a field, the component updated the app-db to which it was also subscribed thus updating the field and moving the cursor to the end of the field whilst the user was typing 2) we had to create an event and a subscription for every field and bind the component to those resulting in lots of boiler plate 3) When returning to a form to enter new details, details from the previous submission were shown Now all of these issues can be categorised as problems with our code, and certainly we can work around them all, but it all adds up to complexity, and one could argue it is entirely unnecessary if the form submit button just gathers the data from the component local state and dispatches a re-frame event with those data to invoke the relevant API call.

p-himik14:01:14

1. This shouldn't be happening unless you're doing something wrong or use a custom input component that Reagent knows nothing about. Hard to tell more without seeing the actual code 2. The power of macros. :) Or plain functions since re-frame registers subs and events via plain functions. I have my own wrappers around re-frame functions that turn the most common usage patterns into one-liners 3. That's just a symptom of an approach that's not compatible with re-frame philosophy. In the latter, data drives everything. If upon form submission you don't clear the old data - that's on you > it is entirely unnecessary if the form submit button just gathers the data from the component local state and dispatches a re-frame event with those data to invoke the relevant API call True. But you can add a handler to the submit event and dispatch and clean-up event in addition to what the browser will already do by itself. Also, don't you intercept that event as it is, regardless of the data storage approach, if you're writing an SPA?

scarytom14:01:24

I think you've missed my point @U2FRKM4TW. We can already answer 1, 2, and 3. My point was: why write all the code to do this if it is unnecessary? What value do we get from using the app-db in this case?

p-himik14:01:21

Global observability (re-frame-10x is fantastic, error logging is trivial), validation (with an option to roll back to the last known user-changed state in case of an error), instrumentation, preservation. All are not specific to re-frame but rather to the data being in a single place, so all of the above are true for e.g. Redux, Flux, etc. I think that in the React world it's now possible to do some of those things at the level of the local data, but I'm not sure how usable it is.

scarytom14:01:47

Thanks. That's the sort of ammunition I was looking for

👍 2
scarytom15:02:42

I colleague of mine pointed me to this thread from Dan Abromov (React core team guru and Redux original author): https://github.com/reduxjs/redux/issues/1287#issuecomment-175351978 I think his insight also applies to the relationship between the re-frame app-db and component local reagent atoms. Anyone have any thoughts on this?

scarytom21:02:24

Thanks @U051MTYAB, I think the difficulty comes in deciding what constitutes a really good reason. I like Dan Abromov's "do whatever is less awkward" rule of thumb. For example, say I have a reusable component for a sortable table. Should the user's chosen sort order go in the app db? If it does, then I have to configure a different db key each time I use the sortable table component, so that the sort orders don't interfere with one another. This feels cumbersome when the state could be local to the component. However, the guidance from @U2FRKM4TW (see earlier in this thread) is that this should definitely go in the app db.

p-himik21:02:24

"Less awkward" acquires a different tone when you put all the benefit of the centralized data storage behind a decision of what is awkward and what isn't.

scarytom22:02:56

but that's exactly the situation Dan's comment is regarding too: he is talking about the centralised data storage of redux, which is pretty much the same as the re-frame app-db

p-himik22:02:20

Yeah, but his comment is void of content. It's basically "do whatever".

p-himik22:02:45

To me, it's incredibly awkward not to be able to see a part of the app's state with re-frame-10x, for example.

scarytom22:02:12

so your main argument for the app db is to make it easier to debug apps?

scarytom22:02:54

I don't think Dan's comment is void of content. He goes into quite a lot of detail in the linked discussion btw

p-himik22:02:05

I believe I have already outlined the benefits that are important to me above.

p-himik22:02:02

I'm referring only to the comment that you linked to. I haven't read the whole discussion. I'm sorry but I won't be able to provide much more input here. Throughout the years, I have seen this question and answered it more times than I can count.

mikethompson22:02:10

Let me put it this way: we use component local state in re-com when creating reusable components pretty much because we have to. "Less awkward" doesn't come into it. "Massively awkward, to the point of unusable" is phrase for what drove that decision. Apart from that we don't ever use component local state. .

scarytom15:02:42
replied to a thread:I have a question about the relationship between the global re-frame app-db and component local state facilitated via reagent atoms. When designing a new component it makes sense for transient state scoped tightly to this component be held in a r/atom local to that component. This avoids polluting the app db and makes it easier to re-use that component. An example might be the current sort-order on table headings, or perhaps the intermediate state of an uncommitted form field. If we have a handful of components, say some specialist form fields, that interact with one another, it can be helpful to create a composite component for those fields and share some local state between them. This can extend to using local state for the form as a whole. My question is, when does it make sense to start leveraging the app db? I find that it makes sense to use the app db to store the results from API calls, rendering views on those data via subscriptions, but it makes less sense to pump form fields via the app-db, instead having form submission send local form state as an argument to the effect handler which makes the writing API call. Thoughts?

I colleague of mine pointed me to this thread from Dan Abromov (React core team guru and Redux original author): https://github.com/reduxjs/redux/issues/1287#issuecomment-175351978 I think his insight also applies to the relationship between the re-frame app-db and component local reagent atoms. Anyone have any thoughts on this?