Brilliant, that helps a ton.

I did the following:

   - Callbacks are hoisted up into a let above the row render function 
   definition.
   - Keys in all the appropriate places.
   - I realized the result of the filter call during deletes (stuck the 
   result into a vec to get rid of the lazy eval)
   - On a whim, turned the row sorting into a subscription, instead of 
   doing it within the table render function.
   
I'm down to about 160-200ms for a row delete now, and 500-600ms for a sort. 
 My sort function takes about 16ms in the worst case (sorting 1,000 uuids) 
to 4ms in the best case (sorting 1,000 integers).

Profile for one of the deletes looks like this:

<https://lh3.googleusercontent.com/-Ay9fOOMAh2M/V8ULk6Tb7PI/AAAAAAAAAGQ/hTXLDPyiBsIxq5keOobfojTG-M9_n9xFACLcB/s1600/Screen%2BShot%2B2016-08-29%2Bat%2B9.18.48%2BPM.png>


(I'm probably learning more than the original poster, thanks!)

On Monday, August 29, 2016 at 7:51:40 PM UTC-7, Mike Thompson wrote:
>
>
>
> Oh, and one other thing.  
>
> Beware callback functions not testing equal to last time.  
>
> You generate (fn [e] (.preventDefault e) (dispatch [:delete (:id row)])) 
> each time.  And that will not test equal to last time ever, even if it is 
> the same fucntion.  
>
> So try to factor out function generation to a Form-2 let, kinda like this 
> sketch ...
>
> (defn row 
>     [row]
>     (let [cb (fn [e] (.preventDefault e) (dispatch [:delete (:id row)])]
>          (fn  [row]
>        [:tr      ;; do not attempt to put a key on here
>           ^{:key 1} [:td (:id row)]
>           ^{:key 2} [:td (:name row)]
>           ^{:key 3} [:td (:value row)]
>           ^{:key 4} [:td [:a {:href "#" :on-click cb "Delete"}]]]))
>
> Make sure you add keys to the row like this in the outer function (ie. do 
> not put a row key inside row):
>
>    (for [r rows]
>       ^{:key (:id r)}[row r])    ;; make sure it is [row r]  and not (row 
> r)
>
>
> On Tuesday, August 30, 2016 at 12:42:36 PM UTC+10, Mike Thompson wrote:
>>
>>
>> Try putting keys onto all the :td. These keys only need to be unique 
>> among peers.  So you can probably just hard code column numbers, like 
>> `{:key "1"}`
>>
>> I'm not at all sure this will work,  but if React is the problem, then we 
>> need to give it all the help we can.  
>>
>>
>> On Tuesday, August 30, 2016 at 8:53:37 AM UTC+10, jona...@mohiji.org 
>> wrote:
>>>
>>> Ok, I gave something similar a try: just rendering a table with 1,000 
>>> rows in it, doing both big and large changes with and without keys.
>>>
>>> My re-frame db is just {:rows []}, where the rows are just maps with 
>>> :id, :name, and :value fields. The :ids are integers, names are strings and 
>>> values are uuids.
>>>
>>> I have a subscription into that db to just grab all the rows out:
>>>
>>> (register-sub :rows
>>>   (fn [db _]
>>>     (reagent/ratom (:rows @db))))
>>>
>>> And a couple of handlers to initialize the db and delete rows out of it:
>>>
>>> (register-handler :init-db
>>>   (fn [db _]
>>>     default-db))
>>>
>>> (register-handler :delete
>>>   [trim-v]
>>>   (fn [db [row]]
>>>     (update-in db [:rows] (fn [rows] (remove #(= row (:id %)) rows))))
>>>
>>> Then I tried rendering the table mostly like this:
>>>
>>> (defn table
>>>   []
>>>   (let [rows (subscribe [:rows])
>>>         sort-key (reagent/atom :id)]
>>>     (fn []
>>>       (let [rows (sort-by @sort-key @rows)]
>>>          [:table
>>>            [:thead (.. header def here, with links to change the 
>>> sort-key atom ..)]
>>>            [:tbody
>>>             (for [row rows]
>>>               ;; ^{:key (:id row)}
>>>               [:tr
>>>                 [:td (:id row)]
>>>                 [:td (:name row)]
>>>                 [:td (:value row)]
>>>                 [:td [:a {:href "#" :on-click (fn [e] (.preventDefault 
>>> e) (dispatch [:delete (:id row)]))} "Delete"]])]]))))
>>>
>>> With that setup, the initial render (e.g. load Chrome's Timeline 
>>> profiler, hit refresh, look for the big render event in there) takes about 
>>> 2 seconds. Re-sorting the table by switching that sort-key atom takes about 
>>> 850ms to re-render without keys, 670 with keys. Deleting rows takes about 
>>> 930ms without keys, 610ms with keys. Totally slow.
>>>
>>> I tried factoring out the row component (which you're already doing 
>>> above) and things improve when keys are in place. The initial render went 
>>> to 2.8s without keys and stayed about 2s with keys. Sorting went way south 
>>> to 6.8s without keys, but 582ms with keys. Deleting is 1.3s without keys, 
>>> 200ms with.
>>>
>>> Looking at the timeline, that last scenario (rows as a separate 
>>> component, with keys) shows about 65ms rebuilding the Hiccup to render the 
>>> table, but only about 8ms of that is spent building the individual rows. 
>>> React's still taking most of the time.
>>>
>>> Trying to think of a way that rearranging the input data might let React 
>>> chew through this faster, but it's not coming to me.
>>>
>>> On Sunday, August 28, 2016 at 3:52:41 PM UTC-7, Marco Laspe wrote:
>>>>
>>>> I think react accepts both. I read it in the docs, that both work.
>>>>
>>>> Either way, it doesn't help. Doesn't matter if the key is metadata 
>>>> befor the [tr , or :key or :data-key. All is slow as f... :(
>>>>
>>>> On Friday, August 26, 2016 at 8:59:09 PM UTC+2, jona...@mohiji.org 
>>>> wrote:
>>>>>
>>>>> It looks like you can also assign the key in the place you're doing it 
>>>>> now, but data-key is the wrong name for it. It should just be :key, like:
>>>>>
>>>>> [:tr {:key (:key t) :on-click h/onclick-task :class class}
>>>>>
>>>>> Honestly, I'm a little surprised data-key isn't getting a complain 
>>>>> from the compiler, unless you have it def-ed somewhere else.
>>>>>
>>>>> On Friday, August 26, 2016 at 11:56:28 AM UTC-7, Walton Hoops wrote:
>>>>>>
>>>>>> That doesn't do it, no. The key is added as metadata to the 
>>>>>> component, for example:
>>>>>> (defn lister [items]
>>>>>>   [:ul
>>>>>>    (for [item items]
>>>>>>      ^{:key item} [:li "Item " item])])
>>>>>>
>>>>>> Interestingly, you are assigning a key to the table, which doesn't 
>>>>>> need one, but not inside your for loop, which could benefit from keys.
>>>>>>
>>>>>> August 26 2016 12:50 PM, "Marco Laspe' via Reagent-Project" <
>>>>>> reagent...@googlegroups.com>
>>>>>> wrote:
>>>>>>
>>>>>> > Thanks for the answer.
>>>>>> > 
>>>>>> > No, react doesn't complain. I think I add a key to every row:
>>>>>> > 
>>>>>> > [:tr {data-key (:key t) :on-click h/onclick-task :class class} ...
>>>>>> > 
>>>>>> > that should do the trick, or do I miss something?
>>>>>> > 
>>>>>> > Best,
>>>>>> > 
>>>>>> > Marco
>>>>>> > 
>>>>>> > On Tuesday, August 23, 2016 at 12:35:50 AM UTC+2, 
>>>>>> jona...@mohiji.org wrote:
>>>>>> > 
>>>>>> >> Does React complain at all about keys in your console? I see that 
>>>>>> you've added a key to the table
>>>>>> >> as a whole, but your individual rows don't have keys assigned to 
>>>>>> them. Try adding ^{:key (:key t)}
>>>>>> >> before your [tr]s and see if it helps out any. I saw a huge 
>>>>>> performance difference when doing
>>>>>> >> something similar: a list of a few hundred almost identical 
>>>>>> elements that stuttered like crazy
>>>>>> >> without the keys, and was butter smooth with them.
>>>>>> >> 
>>>>>> >> On Thursday, August 4, 2016 at 6:49:51 AM UTC-7, Marco Laspe wrote:
>>>>>> >>> Cheers,
>>>>>> >>> 
>>>>>> >>> I am building a task manager with reagent, that has a long table 
>>>>>> (490 rows) of tasks. To create the
>>>>>> >>> table I use following two components:
>>>>>> >>> 
>>>>>> >>> (defn task [t]
>>>>>> >>> 
>>>>>> >>> (let [class (if (= (db/selected) (:key t))
>>>>>> >>> 
>>>>>> >>> "selected"
>>>>>> >>> 
>>>>>> >>> "")]
>>>>>> >>> 
>>>>>> >>> [:tr {data-key (:key t) :on-click h/onclick-task :class class}
>>>>>> >>> 
>>>>>> >>> [:td.taskstate {:on-click h/handle-onclick-taskstate} [:span 
>>>>>> {:class "hover-button"} (:todo t)]]
>>>>>> >>> 
>>>>>> >>> [:td [:span.project-tag.label (:project t)] (:headline t)]
>>>>>> >>> 
>>>>>> >>> [:td.rank [:span.fa.fa-chevron-up.hover-button {:on-click 
>>>>>> h/handle-onclick-up}]]
>>>>>> >>> [:td.rank [:span.fa.fa-chevron-down.hover-button {:on-click 
>>>>>> h/handle-onclick-down}]]]))
>>>>>> >>> 
>>>>>> >>> (defn task-table [tb]
>>>>>> >>> (if (empty? tb)
>>>>>> >>> (empty-message)
>>>>>> >>> [:table.table ^{:key (:todo (first tb))}
>>>>>> >>> [:tbody
>>>>>> >>> (println (count tb))
>>>>>> >>> (for [t tb]
>>>>>> >>> [task t])]]))
>>>>>> >>> 
>>>>>> >>> If I am now changing the state of tb the ui freezes for about 10 
>>>>>> seconds if the task list is this
>>>>>> >>> long. If the tasks list about 100 rows the UI freezes for a half 
>>>>>> second and if the task list has
>>>>>> >>> only a view items it reacts instantly. From the profiler it seems 
>>>>>> as React is doing a lot of stuff
>>>>>> >>> in this case.
>>>>>> >>> 
>>>>>> >>> My question now is: Am I doing something wrong with my 
>>>>>> components. Mike Thompson writes in Eek!
>>>>>> >>> Performance Problems that you should not give the entire state to 
>>>>>> a component if not necessary and
>>>>>> >>> that should divide the UI in more components to have less 
>>>>>> re-rendering. 
>>>>>> >>> 
>>>>>> >>> I think the code above does that. Do I miss something?
>>>>>> >>> 
>>>>>> >>> Best,
>>>>>> >>> Marco
>>>>>> > 
>>>>>> > --
>>>>>> > You received this message because you are subscribed to the Google 
>>>>>> Groups "Reagent-Project" group.
>>>>>> > To unsubscribe from this group and stop receiving emails from it, 
>>>>>> send an email to
>>>>>> > reagent-proje...@googlegroups.com.
>>>>>> > To post to this group, send email to reagent...@googlegroups.com.
>>>>>> > Visit this group at https://groups.google.com/group/reagent-project
>>>>>> .
>>>>>> > For more options, visit https://groups.google.com/d/optout. 
>>>>>>
>>>>>>

-- 
You received this message because you are subscribed to the Google Groups 
"Reagent-Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to reagent-project+unsubscr...@googlegroups.com.
To post to this group, send email to reagent-project@googlegroups.com.
Visit this group at https://groups.google.com/group/reagent-project.
For more options, visit https://groups.google.com/d/optout.

Reply via email to