Fork me on GitHub
#om
<
2015-11-03
>
scriptor00:11:41

figured it out, used :key-fn identity

drcode01:11:18

My first Om Next project is now online: http://lisperati.com/orly

drcode01:11:31

I welcome all feedback regarding proper/improper Om Next usage in this project

drcode01:11:54

(FYI, you should be seeing a bunch of colorful tiles when visiting the demo URL- If you get a blank screen or something let me know your browser version simple_smile )

domkm01:11:55

Hmm, looks like om.core has :key-fn but om.next has :keyfn. Is the inconsistency intentional? I'd consider renaming :keyfn to :key-fn.

domkm01:11:22

Also, data.json uses :key-fn

taylor.sando01:11:01

Probably has to do with how it's named in React

thosmos01:11:50

If we use datascript and all stateful components use an Ident of :db/id, what do we miss? My understanding is that one primary rerender performance boost from Om Next is from using various key names that represent component types, so that when a transact! happens on that type of component, the rerender check can be quickly narrowed down to only those same types of components. is this accurate?

steveb8n01:11:49

I just learned a noob lesson: stating it here for anyone else who might get caught by it. My app follows the pattern shown in the “Components, Identity and Normalization” page. In that case the root query is assembled from a root component and leaf components without including the connecting component. This works in the example but….in my case I am updating local state in the connecting component and the refresh does not include it’s data

steveb8n01:11:43

I fixed it by referencing all components in the tree when building the root query so that refreshes at any level always include the data required.

steveb8n02:11:52

this really clarified for me how much important meta-data is built into the root query - as I stated, a noob mistake. I hope this saves someone else some time

maravillas02:11:51

it looks as though om.next is missing a :require declaration for [cljsjs.react.dom] - noticed when rendering was failing when i used sablono and removed my :require for om.dom

kovasb02:11:16

I wrote a blog about the reconciler, maybe people will find it helpful: https://medium.com/@kovasb/om-next-the-reconciler-af26f02a6fb4

steveb8n02:11:34

@maravillas: I reported the same thing a few days ago. There’s good suggestions for cleaning this up in the discussion.

maravillas02:11:34

ah, excellent

maravillas02:11:46

i worked around it by just referencing om.dom, even though i don't use it

maravillas03:11:51

...which is silly, i guess i could just depend on it directly simple_smile

kurtlazarus03:11:07

@kovasb: Oh wow, thanks for writing this

kurtlazarus03:11:16

still trying to wrap my head around om

thosmos04:11:22

Cool blog post, @kovasb. Very clear

thosmos04:11:33

@kurtlazarus: that's more of a #C053AK3F9 clojure question, and the answer depends on what you want the output to look like. Feel free to message me directly for some help.

kurtlazarus04:11:38

Sorry, didn’t mean to pollute the channel. If anybody else is reading this, I finally figured this out: Here’s a stack overflow where I asked (and then answered) this question: http://stackoverflow.com/questions/33491017/om-next-tutorial-correctly-calling-the-get-people-function/33491426#33491426

hmadelaine08:11:16

@kovasb: very nice overview ! Thank you. You should team up with @tony.kay to write "Om-Next Up and running" 😉

simonb08:11:55

Why is mutate called twice? I put some printlns in the mutate method of the Om Next Datascript tutorial to see how it works. It seems mutate is called twice once with the starting state and once with the updated state, i.e. before and after inc. Anyone know how/why this is? Thanks.

martinklepsch13:11:47

@griffio: I considered that one but decided against it because it’s very hands on and mostly React Native specific. Thanks though!

dnolen14:11:55

added community resources section to wiki, feel free to add blog posts, other docs here https://github.com/omcljs/om/wiki#community-resources

grounded_sage14:11:59

@dnolen: I've been looking into Phoenix framework which uses Elixir... would I be crazy in thinking Om Next and that would make a great combo?

dnolen14:11:38

@grounded_sage: Om Next is agnostic about the backend … so sure!

grounded_sage14:11:41

Awesome. The only other things I would love to use is Transit (which seems not yet ready for production) and Datomic but I might just have to run it through a Peer?

dnolen14:11:17

@grounded_sage: transit is definitely production ready and has been for a long time

dnolen14:11:54

Datomic is great but it’s a bit awkward to use if you aren’t on the JVM

txus14:11:00

I think I’m doing something weird

txus14:11:09

I’m getting "No queries exist for component path” when doing an om/transact!

txus14:11:24

from a child component B

txus14:11:37

it says it can’t find queries for the component path (A B)

txus14:11:50

where A is the parent

dnolen14:11:59

usually means there’s something wrong with the structure of the query

dnolen14:11:25

@txus if you could paste an example of what’s not working it will probably be easy to spot

txus14:11:37

sure, let me grab it

dnolen14:11:40

@txus also you are on the latest alpha I assume?

grounded_sage14:11:07

@dnolen: ok.. Transit website says that it may evolve and to have caution but that must just be for certain use cases. Hmm technology trade offs. So tempted by Elixir scalability and fault tolerance but so many goodies in Clojure land.

txus14:11:18

So this is the parent view:

clojure
(defui RootView
  static om/IQuery
  (query [this]
         (let [sections (om/get-query SectionIconView)
               users (om/get-query UserView)
               software-updates (om/get-query software-updates/SoftwareUpdateView)]
           `[{:app/sections ~sections}
             {:software-updates ~software-updates}
             :app/current-section
             :car/remaining-range
             {:app/users ~users}
             :app/current-user]))
The child view that renders all the SoftwareUpdates:
clojure
(defui SoftwareUpdatesView
  static om/IQuery
  (query [this]
         (let [q (om/get-query SoftwareUpdateView)]
             `[{:software-updates ~q}]))
And the software update view component:
clojure
(defui SoftwareUpdateView
  static om/Ident
  (ident [this {:keys [software-update/name software-update/version]}]
         [:software-update/by-id [name version]])
  static om/IQuery
  (query [this]
         '[:software-update/name
           :software-update/version
           :software-update/size
           :software-update/status])

dnolen14:11:56

@grounded_sage: the warning is just about using Transit as storage format, for wire stuff it’s definitely ready for production usage.

txus14:11:12

(only the queries, to have an idea). One weird thing I’ve noticed is that the RootView grabs onto the SoftwareUpdateView query, and the SoftwareUpdatesView does too, which seems weird. I added the query to SoftwareUpdatesView because I thought that’d fix it, but not sure what’s idiomatic in this case. Is the RootView to do all the orchestration of getting the subquery for the children software updates, or should SoftwareUpdateView do that?

txus14:11:26

Then in the SoftwareUpdatesView there’s a button that width {:onClick #(om/transact! this '[(software-updates/accept)])}

txus14:11:44

s/that width/with/

dnolen15:11:18

@txus yeah so that just isn’t going to work

dnolen15:11:36

the query that is used doesn’t match the component that is going to render it

dnolen15:11:26

that is, you are using another components query to render a component

txus15:11:03

I’m not sure I understand. SoftwareUpdatesView shouldn’t have a query then, because it doesn’t really need it, it just passes down props from the RootView to the children SoftwareUpdateView, yeah?

dnolen15:11:30

@txus there’s no need for every component to have a query, pass through components are fine

txus15:11:21

oh ok. But then if I try to om/transact! from this pass-through component, it doesn’t work right?

dnolen15:11:46

right if you want to transact you must implement IQuery

txus15:11:46

it says transact! invoked by component [object Object] that does not implement IQuery

dnolen15:11:09

and if you need that then fix your queries

dnolen15:11:25

RootView -> SoftwareUpdatesView -> SoftwareUpdateView

dnolen15:11:37

instead of the thing that won’t work as you’ve shown

dnolen15:11:46

RootView -> SoftwareUpdateView

txus15:11:28

okay, so in general you’d say if there’s a tree of components each with more specialized queries, the parent ones shouldn’t bypass the immediate children right?

dnolen15:11:44

it’s not about bypassing

dnolen15:11:49

it’s about breaking a contract

dnolen15:11:03

you cannot pass props computed by something other than the query the component specified

dnolen15:11:12

but that’s what your code does

txus15:11:36

oh shit, I do tend to do thast

txus15:11:56

I’ll keep that in mind. Will study your todomvc again hehe

dnolen15:11:21

one thing you can do here that would make the code much simpler

dnolen15:11:37

remove the query from the child component, move that to SoftwareUpdatesView

dnolen15:11:59

the child component in this case can probably just be pure

txus15:11:57

okay. does that mean though that all children would be re-rendered any time any of the software updates’ data changes?

dnolen15:11:18

no all the usual Om tricks apply

dnolen15:11:21

equality tests etc.

txus15:11:04

will do that then, sorry if the questions are basic! I’m still wrapping my head around it simple_smile

dnolen15:11:37

the query / transact! bits I think are the most challenging to get right

dnolen15:11:48

mostly because what’s allowed is actually pretty restrictive

dnolen15:11:23

@txus actually when I think about it your example (after I gave you the idea for the first fix)

dnolen15:11:01

shows a case where not being able to transact! from IQuery is kind of annoying.

dnolen15:11:08

will have to think about that some more

dnolen15:11:43

@txus yeah this needs some thought, wrote down some notes

txus15:11:35

I’m not sure what you mean by transact!ing from IQuery — I was just transacting from a button callback, not from IQuery itself

dnolen15:11:28

sorry thinking out aloud over here

dnolen15:11:42

I meant transact! from a component that doesn’t implement IQuery

txus15:11:18

@dnolen: in your todomvc I see that parent components pass their whole props to children, is that the preferred way? Intuitively I would’ve thought they’d cherry-pick what to pass down the line

dnolen15:11:50

you cannot cherry pick

dnolen15:11:00

you have to pass whatever the child query specified

txus15:11:15

and that is done automatically right?

dnolen15:11:31

you write that code in your parser

txus15:11:56

ohh right! I forgot

dnolen15:11:11

yeah I keep saying Om Next doesn’t really do anything simple_smile

dnolen15:11:23

it tracks queries and mutations and keeps things in sync

dnolen15:11:32

but all the actual work happens in code users write

dnolen15:11:57

Om Next is really more about uniform app structure and eliminating mutable observation patterns / complications

txus15:11:11

so when you mentioned that child component could be “pure”, as in receive props directly without an IQuery — is that generally not advised, as each component should specify what it needs in IQuery if possible, but then sometimes it’s okay having pure components?

dnolen15:11:25

if a component doesn’t need IQuery don’t implement it

dnolen15:11:58

there’s nothing wrong with a component that doesn’t specify props that you pass props to

dnolen15:11:23

however when a component does specify IQuery you better not mess with those props

dnolen15:11:29

back to your example, so yeah the more I think about it the transact! restriction which was really designed to discourage people using transact! at leaf nodes is just a bad guard-rail

dnolen15:11:42

it prevents perfectly fine cases like your own @txus

txus15:11:42

I guess so, yeah

dnolen15:11:41

hrm but the problem with relaxing this restrition would mean we would need to lift transactions to parents and re-run way more than is necessary.

dnolen15:11:14

@txus so yeah I would probably fix your problem by making all the bits IQuery

dnolen15:11:49

so RootView is something like [{:software-updates (om/get-query SoftwareUpdatesView)}]

dnolen15:11:51

SoftwareUpdatesView is [{:updates/list (om/get-query SoftwareUpdate)}]

dnolen15:11:08

or something like that, and it just avoids all these problems

txus15:11:50

okay, I’ll try that

txus15:11:13

I was just running into a thing with the reconciler, probably the queries are wrong, but I’ve isolated this example:

txus15:11:28

(defui Foo
    static om/IQuery
    (query [this]
           [{:foos [:foo/name]}]))

  (def data {:foos
             [{:foo/name "Foo"}
              {:foo/name "Bar"}]})

  (om/tree->db Foo data true)
  ; {:foos [nil nil], nil {nil {:foo/name Bar}}}

dnolen15:11:38

@txus yeah that won’t work you need to implement Ident for om/tree->db to work

txus15:11:28

I thought that first but then I tried adding

static om/Ident
    (ident [this {:keys [foo/name]}]
           [:foos/by-id name])

txus15:11:50

and I still get {:foos [nil nil], nil {nil {:foo/name Bar}}} :S

dnolen15:11:05

you can’t just add it

dnolen15:11:18

you need at least two components

dnolen15:11:26

Foos & Foo

txus15:11:45

ah! I see what I’m doing wrong ahhhh darn

txus15:11:49

sorry, that was silly!

dnolen15:11:40

yeah I need to write up a best practices page about all this stuff simple_smile

dnolen15:11:56

or a basic query / transact patterns thing

txus15:11:40

between the docs and a couple example apps it’s definitely easy to get going, just some things I guess are a bit new but that’ okay!

dnolen15:11:49

@txus no this is all good feedback!

dnolen15:11:08

a great way to know whether the decisions in place actually make any sense

dnolen15:11:24

and whether it’s a design issue or a documentation issue

dnolen16:11:31

@txus really your question is about query / transaction modularity

dnolen16:11:30

and I’m starting to see that if a component is modular yet involved in transactions, it just has to implement IQuery

txus16:11:20

yeah, it’s okay actually

txus16:11:51

I’ve seen also a different approach in https://github.com/Jannis/om-next-kanban-demo where all transactions are done in the parent view

chris-andrews17:11:51

Hey, I was just looking over the above exchange. So, is the current thought to stick with the idea that any component that wants to transact! something needs to implement IQuery? Something I’ve been hung up on is: what if you have a component like a button, and you want to pass it (as a prop) a callback, which will transact! something? Is that going to blow up?

jannis17:11:44

Not if the callback transact!s against the parent component.

jannis17:11:12

E.g. (button (om/computed props {:on-click #(om/transact! this ...)}))

chris-andrews17:11:15

Ok, that’s what I was hoping would work

chris-andrews17:11:34

Thanks for clarifying that for me

chris-andrews17:11:52

And while we’re on this line of discussion, am I correct in thinking that what is transact!-ed is not limited to updating only aspects of that particular components IQuery? e.g. an action can affect many aspects of the application, even if the transact-er never reads any of that data

chris-andrews17:11:09

@dnolen: hanks. I think I’m starting to get things. But what is the advantage of transact!-ing on behalf of a parent component vs

chris-andrews17:11:27

sorry… vs just letting “dumb” components transact!

dnolen17:11:22

@chris-andrews: I don’t know what you mean

dnolen17:11:35

dumb component shouldn’t transact because they can’t possibly know what other keys are involved

dnolen17:11:42

so it’s just preventing writing spaghetti code

chris-andrews17:11:28

Well, my thought was that the parser has a user-provided mutate function, so any component could transact an increment-thing action, and the parser knows what to do with that, and how to determine which keys should be re-read

chris-andrews17:11:39

I think the gap in my understanding is what keys are used for when transacting, if the transacted actions don’t necessarily have to update only data related to the given component

dnolen17:11:01

right that line of thinking just doesn’t work

dnolen17:11:14

you have to think about remotes

dnolen17:11:21

and the fact clients might not even want those keys

dnolen17:11:08

the only thing that can decide what should reread is UI code

chris-andrews17:11:55

Ok, it’s starting to make sense. I am due for another pass through the docs too. I haven’t read them since way back in the alpha-7 days. Thanks for the help!

drcode18:11:53

"the only thing that can decide what should reread is UI code" Ah... I get why you don't use the ":values" in the mutate functions now!

dnolen22:11:22

wow this is fantastic!

jannis22:11:23

Have you seen the code for the devcards though? It's really just rendering Om Next components, passing props in, not exercising the query and reconciler stuff yet.

dnolen22:11:34

yeah I saw your tweet

dnolen22:11:39

still awesome

jannis22:11:52

The idea of writing and testing UI components in devcards and then combining them in more complex devcards is intriguing for sure. simple_smile

jannis22:11:09

I can imagine scenarios where designers would create sketches in UI cards, developers code them up roughly and then they finish them up together pair-programming-style or something. It's just so quick simple_smile

dnolen22:11:51

@jannis yeah people actually already have really cool working setup of stuff like that

dnolen22:11:06

like Figwheel running in the cloud and pairing with a designer

jannis22:11:13

Really? Nice

dnolen22:11:19

programmer change the code and designer change the styles in parallel

johannjohann22:11:21

that's pretty great

jannis22:11:34

I haven't ever worked with designers, because it's been mostly Linux embedded/desktop work so far. No idea what design processes look like 😉

dnolen22:11:57

yes because Rails has had such a huge effect a lot of people want access to Ruby designer-centric tooling

dnolen22:11:40

I’ve heard of several people using Middleman under JRuby + ClojureScript + Figwheel

maoran22:11:45

Hello, I'm playing with om-next-starter from jdubie and I'm getting a very strange behavior with figwheel... every time I modify the code and save it, figwheel updates the browser code and then I get never ending requests to the server ... not yet figured what's going on...

maoran22:11:49

yes, that solve the pbm... but not understood why

jdubie22:11:03

forgot the push that. just updated github https://github.com/jdubie/om-next-starter