Fork me on GitHub
#om
<
2017-01-20
>
ag02:01:19

If I want some data for component in the state, but I don’t want to add that piece of data to the global app state in reconciler.state, and I’m not using Untangled, so I can’t use uc/InitialAppState protocol, what would be the best/right way of injecting some data related to component from within the component body (I don’t want it to be somewhere else, since it’s used in the component)

ag02:01:47

One way that comes to my mind is to transact this thing right before component mounts, but that slightly complicates things, innit?

anmonteiro03:01:23

@ag sounds like you're looking for component local state

ag03:01:39

nope… I need something that related to the component but in the state atom

ag03:01:55

and I don’t want to use reconciler’s :state key to inject that piece of data

ag03:01:26

I want every instance of the component to be able to pull that data from the state and use it

anmonteiro03:01:27

I don't understand what you're asking then

anmonteiro03:01:18

seems like you want is relatively common - just declare that property in the query and grab it in the parser?

ag03:01:33

but that data does not yet exist in the state though.

ag03:01:29

so let’s say I want a view with a table and I specifically want columns-definitions of that table in the state (so other instances of the table component can use the col-defs)

ag03:01:56

how to I place that data “columns-definitions” into the state?

ag03:01:37

if I just use read method and then return that data from it all the time, then I can’t “generalize" column definitions for multiple tables. I want them to be normalized

ag04:01:45

sorry for confusing you. basically I need something similar to Untangled’s initial-state but without the composition part

anmonteiro04:01:56

I still don't understand what you want specifically that is not possible to do currently

anmonteiro04:01:14

if you want to add stuff to the app-state, transact! a mutation

anmonteiro04:01:42

if you want to have data in the app state initially, just pass that to the reconciler's :state

ag04:01:14

right, but is it ok to transact! in componentWillMount?

raspasov04:01:28

@ag do you need that data to be able to trigger re-renders?

raspasov04:01:48

if sometimes I need data that I’m 100% sure will not be needed to trigger a re-render

raspasov04:01:56

I even place in a separate atom

raspasov04:01:36

it’s isolated cases where you need this, but sometimes I find it useful

raspasov04:01:06

componentWillMount + transact is OK (I think) - I’m sure I’ve done it more than once and haven’t noticed problems

raspasov04:01:01

all of my om.next experience is on React Native but I assume more or less the same in the browser

ag04:01:39

whoah, separate atom? Really, what about “single source of truth” and shit like that?

raspasov04:01:10

yea I know it sounds pretty contrarian 🙂

raspasov04:01:34

that’s a little bit React Native specific but here’s an example

raspasov04:01:49

React Native has those things called “animated values"

raspasov04:01:08

they are inherently mutable things that actually mutate the actual view

raspasov04:01:19

they DO NOT trigger a re-render when they change

raspasov04:01:37

in fact, triggering a re-render as you’re changing them might only make the animation choppy or not perform well

raspasov04:01:45

I saw no point of putting those values inside the main application state (atom …) not that it cannot be done under a separate key; but they really feel “separate” and putting them together with the data that actually triggers re-renders would be, imho, complecting two things

anmonteiro04:01:53

you can always use :shared...

raspasov04:01:55

tbh, this probably does not apply to the browser at all, just wanted to explain my reasoning 🙂

raspasov04:01:26

@anmonteiro I don’t think I knew about shared when I made that decision but you’re probably right 🙂

raspasov04:01:55

@anmonteiro I learned about om/computed a few days ago!!! I was like “OMG” haha

raspasov04:01:07

imo it should be in the first tutorial

raspasov04:01:22

it’s such a useful thing sometimes…

anmonteiro04:01:27

it is indeed useful

raspasov04:01:48

if you see the hacks that I invented to go around thius

raspasov04:01:55

before I knew about computed

anmonteiro04:01:00

I don't think any Om contributor has time to work on tutorials right now

raspasov04:01:03

you’ll probably laugh 😄

anmonteiro04:01:13

but a blog post explaining that would probably be helpful?

anmonteiro04:01:47

if you already have a blog set up, etc.

raspasov04:01:21

yes, on a free day I would write a thing about it… it’s really a more of an “advanced” feature, a paragraph would be more than enough

raspasov04:01:26

I know it’s already in the docs

raspasov04:01:36

I just didn’t read them fully (which is my bad)

raspasov04:01:23

before I knew about om/compute I would pass, say a fn, just as a prop

raspasov04:01:55

but that’s bad, since (I think) then it just triggers a re-render every single time (I think)? or it doesn’t actually trigger, I don’t remember

raspasov04:01:14

I remember it creating some weird behavior that took me a few hours to debug

anmonteiro04:01:30

the problem that computed solves is that on re-render your props will disappear if they're not part of the query

raspasov04:01:56

yes, so basically previously I re-invented computed 🙂

raspasov04:01:02

where in componentWillMount

raspasov04:01:19

I’ll grab any prop that say begins like :-init-*

raspasov04:01:31

and store it in local state 😂

raspasov04:01:41

does a change to computed actually trigger a re-render?

raspasov04:01:57

Of the component?

anmonteiro04:01:03

can't remember. I don't think it does

raspasov04:01:19

yea that would make sense, I didn’t think so.. (not sure 100% either)

raspasov04:01:25

I didn’t know about this either! 🙂 Good point, you’re most likely correct

raspasov04:01:45

one indication of good software is when you keep discovering over time features that solve your subtle problems 🙂

ag04:01:31

Antonio. you should start writing a book.

ag04:01:31

co-author it with Tony Kay

claudiu07:01:48

Hi, Would you recommend starting a new project with untangled ? Are there any disadvantages to using untangled instead of just om.next ?

Yehonathan Sharvit09:01:32

What is the best way to prevent a mutation from occurring twice?

danielstockton09:01:25

@viebel any more context? I would answer 'not running it twice'..

danielstockton09:01:40

Make sure any side effects are in the :action thunk, not in the parser fn body

Yehonathan Sharvit09:01:55

If you press the button, and open the browser console, you’ll see twice the printing of “mutate"

danielstockton09:01:08

That's normal viebel, which is why you put side effects in the :action key

danielstockton09:01:12

Is it ever ok to use (.forceUpdate this)? I have a sidebar which updates the query on a parent (filter, search options...) and unless the props change, it doesn't re-render with the new options. I found (.forceUpdate this) fixes it, in componentWillRecieveProps.

hlolli09:01:33

@viebel is this klipse.tech your own personal gist or can anyone paste (or embed) their own gists and make a link like that?

Yehonathan Sharvit09:01:20

anyone can embed their own gist with the cljs_in.gist url param

hlolli09:01:20

ahhh bingo, nice nice nice.

Yehonathan Sharvit09:01:12

Waiting for your gist @hlolli ...

Yehonathan Sharvit09:01:26

(don’t forget the container=1 url param!!)

hlolli09:01:39

I've never made a github gist, just tried pasting some random cljs gist and it worked. But Im not gonna keep you waiting, I make one gist, 5 mins...

Yehonathan Sharvit12:01:38

I hope people will start using this interactive gist system for sharing stuff or asking questions on this channel cljs😃cljs

hlolli12:01:28

yes, basically why doesnt my code work + someone edits the code = no miscommunication*fun

Yehonathan Sharvit12:01:37

I have in klipse's backlog the idea of allowing people to save/fork gists directly from klipse so it will be even more fun

hlolli13:01:28

I see myself wanting to make my own browser text editor, then I can take my nerdy powers into parties without laptop and show off my cljs skills 😄

tmulvaney14:01:08

If I in my UI I have a component whose query returns a {:remote true} because state is missing, do I expect that component to mount after that novelty has been received or before?

tmulvaney14:01:44

The component seems to be mounting for me and the om/props are nil

danielstockton14:01:52

@tmulvaney it probably depends if its the root component or rendered conditionally

tmulvaney14:01:24

I'm using compassus so it's a component rendered depending on the route

danielstockton14:01:25

I believe it will mount before the novelty is received then

tmulvaney14:01:16

Yeah thats what i'm seeing. It's only annoying because the component has an ident which obviously can't be satisfied until the novelty comes in.

tmulvaney14:01:43

I think someone else ran into this, i'll have to browse the logs...

danielstockton14:01:06

Actually no, mine mounts after receiving props, you must be returning {:value nil} from your parser?

tmulvaney14:01:16

I double checked that and I'm not... I must be doing something silly elsewhere...

danielstockton14:01:41

forget that, mine is only not nil because i pass some computed props through from my wrapper

danielstockton14:01:46

i think it is normal, what you're seeing

tmulvaney14:01:37

Yeah it wasn't a problem for me earlier as the entry point was always the index page

tmulvaney14:01:55

but now i have server side rendering in place so one can enter from any page...

danielstockton14:01:13

you should be able to place this component deeper in the tree and render it conditionally based on the presence of the needed props?

danielstockton14:01:52

are you trying to build a detail view for some object?

tmulvaney14:01:41

Yeah but the issue is the page is already rendered, so the component that was rendered by the server will disappear while novely is being fetched to render the same thing

tmulvaney14:01:19

Might just need some more thinking as i'm new to server side react

danielstockton14:01:46

I don't have any experience in server side rendering, i know that for a detail page i worked on recently, i wrapped the component with an ident with another component that didnt have an ident, with a (when props clause in render

danielstockton14:01:44

are you using foam? isnt there a way to bootstrap the app-state so it doesn't make the remote call?

tmulvaney14:01:06

No I'm using om.next's server side rendering. Quite fancy, and so far trivial to get rendering.

tmulvaney14:01:55

But now I'm stumped as to what to do when its the clients job to take over.

tmulvaney15:01:09

So I think I can get around this if I get the initial root query and then somehow gave that to the reconciler, then after reconciliation mount the app so all the initial state is set. But I don't know if there are fns exist for A) passing the initial query to the reconciler and B) checking if reconciliation is complete. I could also be completely off track as to how I think i should be solving this. This seems to be the Relay approach when doing server side rendering.

hlolli16:01:36

om next quiz of the day: How do I get C props: {:data-3 {:e 5 :f 6}} displayed on the page via joins?

ag22:01:58

if I transact something that adds data into the state (in denormalized form, in componentWIllMount) should I expect things to be normalized automatically, if in the Root component I have a query with the correct ident?

anmonteiro22:01:06

the simple answer is no.

anmonteiro22:01:37

but it depends where your data is coming from

anmonteiro22:01:18

if you have :normalize true in the reconciler and your data is coming from a remote, it'll probably get normalized

ag22:01:31

no, data is not coming from the back-end, it’s getting injected in “willMount"

ag22:01:50

so how do I force data normalization, when I mutate state? e.g. I need to add :users/by-id :Phil, to :users, how do I do that?

ag22:01:23

transact and normalize All the :users and then update the state? i.e. assoc @state :users (:users normalized) :users/by-id (:users/by-id normalized)?

ag22:01:42

that involves merging om.tables, etc

anmonteiro23:01:27

@ag normalize that data yourself with either tree->db or manually

ag23:01:31

hmmm… that’s a bit painful, ok

ag23:01:36

thanks Antonio

ag23:01:44

@anmonteiro can’t think of better way:

(defn normalize-into-state
  "normalizes given data by applying om/tree->db
   then merges it to the state
   and properly updates :om.next/tables"
  [state query data]
  (let [normalized (om/tree->db query data true)]
    (-> state
        (merge state (dissoc normalized :om.next/tables))
        (assoc :om.next/tables
               (apply clojure.set/union (map :om.next/tables [state normalized]))))))

anmonteiro23:01:05

notice that'll overwrite any properties you may already have in state

ag23:01:25

well, technically it should overwrite only the data being normalized, so if say I’m applying :app.users (with the right query) it should replace :app.users and every :app.user/by-id

anmonteiro23:01:54

@ag I don't know what your use case is, but what I'm saying is if you have data in :app.user/by-id already it'll get overwritten with the new one

ag23:01:48

correct. because I’m re-normalizing entire :app.users

ag23:01:19

I tested with a simple query, I assume it should work for any queries, e.g: [{:app.data (get-query AppDataIdent)}{:app.users (get-query UserIdent)}]