In Marionette JS, re-rendering large lists while keeping performance high can be difficult.
Marionette abstracts a lot of the hard parts from you; however, there are still several anti-patterns that permeate apps, slowing render times down to a crawl.
Here are a few solutions to speed things up. They are not perfect for all applications, but they have worked well for me in the past.
Case #1: Minimize the work in onRender
itemView onRender jQuery calls when you have multiple rerenders of a collectionView
The client comes to you and asks, on hover of an item in this list, I should see a tooltip with the long title.
A simple task for CollectionViews
and ItemViews
—or at least it seems.
Assuming an itemView
as follows:
class Cat extends Marionette.ItemView
# ...
onRender: ->
@$('[title]').tooltip()
This is going to give you exactly what you want. However, when your list is large, this is going to significantly slow down your render speed. Why? Because each of your itemViews
will execute this code within the addItemView
method on the collectionView
.
The solution is to pull this UI interaction behavior out of the itemViews
and into the collectionView
.
class CatList extends Marionette.CollectionView
onRender: ->
@$('[title]').tooltip()
Now the tooltip behavior runs once after all of your items have been rendered.
Case #2: filtering at an itemView level
React to model changes to toggle visibility within a collectionView, without rerendering the entire collection
Filtering is the bane of many developers. Perhaps in your UX when a user syncs with the persistence layer, single models in your collection will change one of their attributes which then will be represented in the UI by hiding the itemView
.
Assuming an itemView
as follows
class Crayon extends Marionette.ItemView
# ...
modelEvents: ->
change:color: @handleVisibility
handleVisibility: ->
if @model.get('color') is "red" then @$el.hide() else @$el.show()
This optimization is handy when you want your collectionView
to be a bit dumb and want to let the itemView
s determine their own visibility status in the UI.
Case #3: filtering at a collectionView level
Handle view visibility during collectionView rendering, without having to render your entire collection
When you have a large collection and want to display a subset of that list, there are several solutions. You can create a new collection containing the models, or use a backbone plugin to give your collection filter behaviors.
Here is an approach that I use from within the collectionView
.
class People extends Marionette.CollectionView
addItemView: (item) ->
super if item.shouldBeShown()
This works well because all models hit addItemView
before they are rendered; thus you can short-circuit the entire render logic if the model does not pass your render conditions.
Hopefully this helps you on your way to building more performant web applications!
Sam Saccone - @samccone