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.