Masonry
The following is a WIP spec for where the Masonry code is headed. Is not representative of the current codebase
Description of Masonry rendering algorithm.
Masonry Specification
let ITEMS_PER_INSERTION
be an integer describing the number of items to insert per frame. Defaults to 1.
CalculateItemPosition()
New position is defined as { column, top, left, bottom} where:
column
= measurementStore.getShortestColumn()top
= measurementStore.getColumnHeight(column)left
= column
* this.itemWidthbottom
= top
+ itemHeight + this.gutterWidth;
ItemRefCallback(ref:HTMLElement, itemKey:string)
- If
ItemMeasurementStore
does not contain measurement
- Measure the ref HTMLElement
- Update
ItemMeasurementStore
with the height of the element.
- If
ItemPositionStore
does not contain position,
- Run
CalculateItemPosition
to get the position of the item. - Update
ItemPositionStore
with the calculated item position.
- Remove the item entry from
state.pendingMeasurementItems
. - Add the item entry to
state.gridItems
via setState
let state
= {
gridItems: Array,
pendingMeasurementItems: Array,
pendingInsertionMeasurementItems: Array<{itemType, columnIdx, rowIdx}>
};
let props
= {
items: Array,
};
Masonry Lifecycle
- Masonry Server Render and Hydration
- constructor()
- Set
this.insertedItemPointer
equal to the length of props.items
.
- render()
- Map over
state.gridItems
until reaching an index equal to this.itemRefPointer
and render all items as ComponentWrapper
instances. - Specify
ItemRefCallback
as a ref for each ComponentWrapper
.
- (Client Hydration) render()
- Item ref callback fires for each item.
- componentDidUpdate()
- loadMoreItems()
- Additional items are populated in the
items
prop. - componentWillReceiveProps()
- Compare
newProps.items
against this.props.items
- If anything is different between the items, reflow the grid
- If new items have been inserted, call
insertItems
with newProps.items.slice(this.insertedItemPointer)
- insertItems(nextItems)
- Let
newItems
be a slice of nextItems
from 0 to MAX_ITEMS_PER_INSERTION
- Increase
this.insertedItemPointer
by length of newItems
- Append new items into
state.pendingMeasurementItems
via setState
- render()
- Render all items in
state.pendingMeasurementItems
inside a ComponentWrapper
with visibility of hidden. - Render all items in
state.pendingInsertionMeasurementItems
inside a ComponentWrapper
with visibility of hidden. ItemRefCallback
is called for each item in state.pendingMeasurementItems
and state.pendingInsertionMeasurementItems
ItemRefCallback
- Updates measurements/positions
- Updates
state.gridItems
and state.pendingMeasurementItems
- render()
- setStateCallback - call insertItems() with
this.props.items.slice(this.insertedItemPointer)
on the next frame
ItemPositionStore
updateColumnHeight
- If inserting into a row before the current position in column
- Update all following item positions.
setItemPosition
- Sets item position in the store for a given key and position.