The biggest things for me are that:
1. Components shouldn't know anything about the structure of the state
other than what they need themselves - that means that they shouldn't
themselves know what path gets to the state they act on and they shouldn't
care what's below that path (other than for what they render/modify
themselves)
2. Parent components shouldn't have to know about what the child
components need, especially distant children. That is, if I have a tab
component which contains a list component where each list element component
contains a component that shows if the content meets some criteria and that
criteria is specified on a completely different path in the state, then the
tab, list and list elements shouldn't need to know about that. Yet updating
the criteria should automatically update everything appropriately.
I'm not sure if something like (om/get-shared owner [:app-state
:foo])meets these two requirements since the component would need to
know the
path to the data it needs, though I guess you could pass that information
in as opts or otherwise. I'd like some way of configuring all of this
externally, maybe as part of root, but then how do you get it to the
correct components?
An approach might be that you can (optionally) tag a component with a
keyword *(maybe use the :key or :react-key? though it should probably also
be possible for the component set its own key rather than (or as well as)
the parent passing it to build - maybe)* and then in the root you can do
something like :cursors {:my-component-key #{[:path1] [:path2]}} and the
paths would be merged into whatever the parent passes to build. Or
potentially even better - something like what Sean Grove uses, where you
have a function that selects (and possibly reformats) the data: :cursors
{:my-component my-transform-fn}
At least, that's my opinion on the subject.
On 10 April 2014 10:02, Dimitris Stefanidis <[email protected]> wrote:
> I was thinking about the same too and was trying to find a way to apply
> this in om since this problem appears too often.
>
> It would be nice if I could have a products vector in my state and a
> selected products vector. The products list component would get both
> products and selected products cursors and would add any selected items in
> the selected products cursor. Other components could get the selected
> products cursor and display summaries detailed lists e.t.c.
>
> This way components do not have to know anything about the structure of
> the application state. Of course there might be other caveats in this
> approach that are probably missing me.
>
> On Thursday, April 10, 2014 11:49:03 AM UTC+3, Jack Schaedler wrote:
> > Does it make any sense to allow components to reference multiple
> cursors? Instead of specifying a single path into the application state,
> you would specify a collection of paths within the state atom, all of which
> would trigger re-renders and allow for transact! and update!? I often find
> myself pulling component cursor paths 'up' the tree in order to ensure that
> the cursor is broad enough to capture all of the state changes that might
> cause a re-render.
> >
> >
> >
> > That being said, I still have the feeling that in the majority of cases,
> the confined scope of the cursor guides me towards a more sensible layout
> of the application state.
> >
> >
> >
> >
> >
> > On Thursday, April 10, 2014 4:12:31 AM UTC+2, David Nolen wrote:
> >
> > > Yes it's a problem that you encounter in React if you try to do things
> in a functional manner. It's not really a "limitation" of React or Om. But
> at least in the case of Om I consider it a deficiency great enough to build
> direct support so that users aren't hampered by it or forced to come up
> with their own ad-hoc solutions.
> >
> > >
> >
> > >
> >
> > >
> >
> > > David
> >
> > >
> >
> > >
> >
> > >
> >
> > > On Wed, Apr 9, 2014 at 10:05 PM, Brendan Stromberger <
> [email protected]> wrote:
> >
> > >
> >
> > > I've encountered this issue in vanilla React (js), and couldn't figure
> out any other way than munging my data together such that I could pass it
> down in the way OP describes. I guess my question is, is this limitation
> inherent in React or in the Om abstraction?
> >
> > >
> >
> > >
> >
> > >
> >
> > >
> >
> > >
> >
> > > On Wednesday, April 9, 2014 3:52:05 AM UTC-7, David Nolen wrote:
> >
> > >
> >
> > > > You're not missing anything. This is a fundamental issue in Om right
> now and I've been designing and working on a fix. Basically in the very
> near future a component will be able to access something in the application
> state without needing a parent component to pass it in from above.
> >
> > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > The idea is that a component will be able to get its data directly
> from the app state with something like (om/get-shared owner [:app-state
> :foo]).
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > Still working out the details, but this work is happening in the
> `ind-components` branch. When it's finished there'll be an accompanying
> nested tab view example - one of the cases that suffers the most under the
> current system.
> >
> > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > David
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > >
> >
> > > > On Wed, Apr 9, 2014 at 6:33 AM, Daniel Kersten <[email protected]>
> wrote:
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > Hi,
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > I'm trying to figure out the best way of structuring complex
> applications in Om and I've hit a bit of a brick wall that I'm hoping
> someone can help me with.
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > I like the concept of cursors - narrow down the application state to
> what the individual components actually need and allow them to read and
> modify only that.
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > The problem I'm having is that I don't know how to structure my
> state so that the correct components have access to everything they need.
> Its easy if each component only requires a strict subset of its parent,
> which is often the case, but not always. I've hit a scenario where a
> component needs access to two very different branches of the app state and
> I'm not sure how to pass it to the component that needs it.
> >
> > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > As a (contrived) example, imagine you had an app for displaying
> orders in an online store and the application state is something like this:
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > (def app-state (atom {:items [{:type "book" :price 123} {:type "cd"
> :price 200}]
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > :orders [{:date xxx :type "book" :count 3}
> {:date yyy :type "cd" :count 1}]
> >
> > >
> >
> > > > :filter "book"}))
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > You can imagine that in a real application the :items and :orders
> branches may be much deeper.
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > Lets say I now have two components, one displaying the items (so it
> is passed a cursor with path [:items]) and one displaying the orders (so it
> is passed a cursor with path [:orders]). What if I now only want to display
> items and orders where the type matches the filter?
> >
> > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > I have a few options:
> >
> > >
> >
> > > > Restructure the app state in a way that gives each component access
> to what it needs. This is not ideal as it means that I'm modelling my state
> after how its being rendered rather than how its being processed and makes
> it very application specific.
> >
> > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > I can propagate the additional values down the component tree (eg
> using the :state parameter to build), but this means that every other
> component before the one that consumes it must now do additional work that
> it shouldn't need to know about (couples the parent components too tightly
> to the child one)
> >
> > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > Similarly, passing it in opts is not ideal as it has the same issue
> as #2, with the added caveat that the component also won't rerender on
> change.I can store the value in component local state and update it through
> a core.async channel. This works well in the example above, where one or
> two simple values need to be communicated, but gets unruly when the
> application is more complex.
> >
> > >
> >
> > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > I can pass the entire app state to each component (perhaps trough
> shared state) and use transformation functions (similar to what Sean Grove
> did in his recent slides) to transform the state into a local view for each
> component. This means each component gets to select exactly what it needs
> to access without worrying about what comes before or after it in the
> hierarchy, but then you lose the benefit of cursors and automatic
> re-rendering when something changes.
> >
> > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > I'm sure I'm missing something!
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > Any tips appreciated.
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > Dan.
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > --
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > Note that posts from new members are moderated - please be patient
> with your first post.
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > ---
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > You received this message because you are subscribed to the Google
> Groups "ClojureScript" group.
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > To unsubscribe from this group and stop receiving emails from it,
> send an email to [email protected].
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > To post to this group, send email to [email protected].
> >
> > >
> >
> > >
> >
> > >
> >
> > > >
> >
> > >
> >
> > > > Visit this group at http://groups.google.com/group/clojurescript.
> >
> > >
> >
> > >
> >
> > >
> >
> > > --
> >
> > >
> >
> > > Note that posts from new members are moderated - please be patient
> with your first post.
> >
> > >
> >
> > > ---
> >
> > >
> >
> > > You received this message because you are subscribed to the Google
> Groups "ClojureScript" group.
> >
> > >
> >
> > > To unsubscribe from this group and stop receiving emails from it, send
> an email to [email protected].
> >
> > >
> >
> > > To post to this group, send email to [email protected].
> >
> > >
> >
> > > Visit this group at http://groups.google.com/group/clojurescript.
>
> --
> Note that posts from new members are moderated - please be patient with
> your first post.
> ---
> You received this message because you are subscribed to the Google Groups
> "ClojureScript" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To post to this group, send email to [email protected].
> Visit this group at http://groups.google.com/group/clojurescript.
>
--
Note that posts from new members are moderated - please be patient with your
first post.
---
You received this message because you are subscribed to the Google Groups
"ClojureScript" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/clojurescript.