mediumReact Native#134

Symmetrical Grid (Grilla Simétrica)

Prompt

Create a horizontally-scrolling balanced masonry grid using Flexbox. Images should be added dynamically, creating new columns not rows. No empty vertical spaces between items.

Solution

export default function SymmetricalGrid() {
  const [items, setItems] = useState([{ h: 100 }, { h: 200 }, { h: 150 }, { h: 180 }, { h: 120 }])
  const addItem = () => setItems(prev => [...prev, { h: 100 + Math.random() * 150 }])
  const columns = items.reduce((cols, item, i) => {
    const colIdx = i % 3
    if (!cols[colIdx]) cols[colIdx] = []
    cols[colIdx].push(item)
    return cols
  }, [])
  return (
    <View>
      <ScrollView horizontal>
        <View style={{ flexDirection: 'row', gap: 4 }}>
          {columns.map((col, i) => (
            <View key={i} style={{ gap: 4 }}>
              {col.map((item, j) => <View key={j} style={{ width: 100, height: item.h, backgroundColor: '#ccc', borderRadius: 4 }} />)}
            </View>
          ))}
        </View>
      </ScrollView>
      <Button title="Add" onPress={addItem} />
    </View>
  )
}
Mentor's take

The insight being tested: React Native has no CSS columns or grid, so masonry is a data transform, not a style trick. You reshape the flat items array into an array of column arrays — here reduce dealing item i into column i % 3 — and then the layout is trivial: a horizontal ScrollView wrapping a flexDirection: 'row' container, each column a plain vertical View stack. Because each column stacks its own items with no absolute positioning, there are no vertical gaps by construction.

Trade-offs a senior states up front:

  • Round-robin (i % 3) balances item count, not height. Three tall images can land in one column. True masonry is a greedy variant of the same reduce: push each item into whichever column currently has the smallest summed height. Same structure, one extra comparison — worth mentioning even if you ship round-robin in the timebox.
  • The transform runs in render. For dozens of tiles that's free; wrap it in useMemo keyed on items before reaching for anything heavier.
  • Index keys here are a nuance, not an outright sin: columns are fixed positional slots, so key={i} on columns is stable. Item keys within a column do shift as new items redistribute — with real image data you'd key on the image id.

Red flag: absolute-positioning every tile with hand-computed offsets. You've reimplemented the layout engine, badly, and rotation/resize breaks it.

Say it: "Masonry in RN is a reduce that reshapes items into columns — flexbox does the rest, and swapping round-robin for shortest-column is one comparison away."