2

I have a <List /> inside an <InfiniteLoader />, inside an <AutoSizer />, also <WindowScroller /> and <WindowScroller /> (wow, so much hocs there) but for simplicity, I think my question could fit the same with a simple <List /> Component.

I'm not sure if there is a way to render some kind of separator or heading like a title for the section (piece of data) rendered below.

Since each item have a prop that allow to group the data in chunks, and I am receiving this data ordered and grouped like:

[
  {
    item: 1,
    name: 'Banana',
    kind: 'fruits',
  },
  {
    item: 2,
    name: 'Apple',
    kind: 'fruits',
  },
  {
    item: 3,
    name: 'Watermelon',
    kind: 'fruits',
  },
  {
    item: 4,
    name: 'Dog',
    kind: 'animals',
  },
  {
    item: 5,
    name: 'Cat',
    kind: 'animals',
  },
  {
    item: 6,
    name: 'Horse',
    kind: 'animals',
  },
//...
]

the idea is to render something like:

<ul>
  <li className="fullWidth">
    <h3>Fruits</h3>
  </li>
  <li>Banana</li>
  <li>Apple</li>
  <li>Watermelon</li>
  <li className="fullWidth">
    <h3>Animals</h3>
  </li>
  <li>Dog</li>
  <li>Cat</li>
  <li>Horse</li>
</ul>

Making some calculation in rowRenderer method?

Or, since I am wrapping the <List /> in an <InfiniteLoader /> I could pass an argument when fire loadMoreRows, but anyway I think I have to do some calculation in rowRenderer, the responsible for the final render.

Lionel T
  • 1,559
  • 1
  • 13
  • 30

1 Answers1

2

This is possible, although much easier if your data is pre-sorted so that groups aren't interleaved. You basically have 2 options:

  1. Pre-flatten your data into an array of 2 types of items. One type is a header and the other type is a child. If you want headers to be a different size than regular rows you'll need to also provide a rowHeight getter function that's able to distinguish between a header item and a child and return a different value. Your rowRenderer will also need to do the same.
  2. Compare the current datum's "kind" to the one that came before it and include a header with the rendered row if they are different. This approach also requires a custom rowHeight getter but does not require any data flattening so it may be easier/faster. The only downside is that your header and row item will be within the same div (or li) if you approach this way.

Here's an example of option 2: https://plnkr.co/edit/l22Ir7?p=preview

And here is the relevant code bits:

function includeHeader(index) {
  return (
    index === 0 ||
    list[index].kind !== list[index - 1].kind
  );
}

function rowHeight({ index }) {
  return includeHeader(index)
    ? ROW_HEIGHT_WITH_HEADER
    : ROW_HEIGHT;
}

function rowRenderer({ index, isScrolling, key, style }) {
  const datum = list[index];

  return (
    <div
      className='Row'
      key={key}
      style={style}
    >
      {includeHeader(index) && (
        <h3>{...}</h3>
      )}
      <div>{...}</div>
    </div>
  );
}
bvaughn
  • 13,300
  • 45
  • 46
  • Thank for the reply and sorry for the delay, I was fiddling with the code you proposed. I think I had to include in the question, the fact that I am using `flexbox` to render items in rows, something like this [plunker](https://plnkr.co/edit/vNHDmpEY2bjQbCup4xsG?p=preview) used in another [question you answered a while ago](http://stackoverflow.com/questions/42095839/add-padding-top-in-react-virtualized-list?answertab=active#tab-top). So with this _approach_ could need the _Header_ a `Row` where are different `kind` of items – Lionel T Apr 26 '17 at 16:47
  • [Here is a plunker](https://plnkr.co/edit/3kVJf0YM3CI9HQ5CG3cI?p=preview) where I applied part of your _approach_ but there isn't what I loking for. Basically, the red box should be an entire `Row` and need to render a pre-row-header with the `list[index - 1].kind` items, and a post-row-header with the `list[index].kind` items or something similar. – Lionel T Apr 26 '17 at 16:56
  • This update makes the answer more complex. Given this, I would recommend you go with option 1. You'll have to take into account the fact that you're wrapping multiple items into a single "row" when you're flattening the data. Also resized widths will require you to recalculate the flattened array. Unfortunately I don't really have the time to create a Plnkr showing this. – bvaughn Apr 26 '17 at 22:51
  • no worries about the Plnkr and thanks a lot for the tips and tricks. – Lionel T Apr 27 '17 at 04:46