React-virtualized: How to get the visible data in the FlexTable?

Created on 15 Jun 2016  路  15Comments  路  Source: bvaughn/react-virtualized

I want to get a list of all records that are visible in the table. I want to do this onScroll.

The only documented public methods are measureAllRows and recomputeRowHeights. Is there another way?

discussion question

Most helpful comment

Sounds like a lacking implementation.

Sounds like a poor choice of words. A _lot_ of thought and testing (and time) has gone into optimizing scroll performance of this library. The fact that it doesn't handle _this_ particular use case doesn't suggest anything about the quality of the implementation.

All 15 comments

Never mind. I just realised that there is an event onRowsRendered, which:

Callback invoked with information about the slice of rows that were just rendered: ({ overscanStartIndex: number, overscanStopIndex: number, startIndex: number, stopIndex: number }): void

This is not ideal though. It requires storing startIndex, stopIndex in the state, which triggers an update (, which can be prevented using custom shouldComponentUpdate logic).

Is there a functional way to get the current slice?, i.e. using a ref to the FlexTable and calling a method to retrieve the data.

Looking at the current source code (https://github.com/bvaughn/react-virtualized/blob/master/source/FlexTable/FlexTable.js) - no, there is not. It would be a useful addition.

This is not ideal though. It requires storing startIndex, stopIndex in the state, which triggers an update (, which can be prevented using custom shouldComponentUpdate logic).

Is there a functional way to get the current slice?, i.e. using a ref to the FlexTable and calling a method to retrieve the data.

Looking at the current source code (https://github.com/bvaughn/react-virtualized/blob/master/source/FlexTable/FlexTable.js) - no, there is not. It would be a useful addition.

Event approach does not work, because onScroll is called before onRowsRendered. Even if we use onRowsRendered to get save current {startIndex, stopIndex} in the state, this will not represent the current rows when onScroll fires.

Never mind. I just realised that there is an event onRowsRendered
This is not ideal though. It requires storing startIndex, stopIndex in the state, which triggers an update (, which can be prevented using custom shouldComponentUpdate logic).

The indices only need to be stored in state if you want them to trigger a re-render. If you don't- (it sounds like you don't)- then just store them as "private" instance variables. eg

<Grid
  {...otherGridProps}
  onRowsRendered={({ startIndex, stopIndex }) => {
    // Store for later use without triggering a re-render
    this._startIndex = startIndex
    this._stopIndex = stopIndex

    // If the changed indices require you to update, then...
    this.setState({})
  }}
/>

The indices only need to be stored in state if you want them to trigger a re-render. If you don't- (it sounds like you don't)- then just store them as "private" instance variables. eg

As I said in the earlier comment, this is not useful because onScroll fires before onRowsRendered, i.e. onScroll has only access to stale data.

You said that about onScroll yes, but the snippet I post above is onRowsRendered.

Ah, sorry. I just re-read your description and I understand your previous comment now.

The problem with what you're asking is that- as of onScroll- the rows rendered in the table/grid/list are actually still the previous rows. It isn't until the next render (triggered by the scroll) that the indices are updated. So the information you want to fetch doesn't exist at that time; even if I added a method it would have "stale" information unless you waited for the next render. (I recommended onRowsRendered for this reason; it is called when the rows are first updated.)

Perhaps you could explain your use case a little more.

The problem with what you're asking is that- as of onScroll- the rows rendered in the table/grid/list are actually still the previous rows. It isn't until the next render (triggered by the scroll) that the indices are updated.

Sounds like a lacking implementation. A simple solution: You could delay onScroll event propagation to the client until after the onRowsRendered. This way onScroll event propagated to the user would be able to describe the current rendered rows.

(I recommended onRowsRendered for this reason; it is called when the rows are first updated.)
Perhaps you could explain your use case a little more.

We have many tables on the screen. We are using data from the top visible row in the table to adjust scroll of all related tables, e.g. Imagine one table that lists sales (columns: id, time, price) and another table that lists purchases (columns: id, time, price). When user scrolls sales table, we'd use "time" value of the top visible row in the sales table to find the nearest time in the purchases table and adjust purchases table scroll to reflect that time window.

Note that rows in sales and purchases do not have 1 to 1 mapping, therefore it is not as simple as offsetting one table scroll by as much as the other table scroll offset is.

Sounds like a lacking implementation.

Sounds like a poor choice of words. A _lot_ of thought and testing (and time) has gone into optimizing scroll performance of this library. The fact that it doesn't handle _this_ particular use case doesn't suggest anything about the quality of the implementation.

I have thought a bit in the past about pre-calculating the visible row range (ahead of render time, in componentWillUpdate for example) and I think I even tried that in a branch at one point- although it's been a couple of months and I'm not sure I recall why it didn't stick. It would be a non-trivial change to make to Grid though and it would have implications for HOCs like CellMeasurer (which may be good or bad, unclear at the moment).

As for delaying the onScroll I think that would make things feel unresponsive. Scrolling already can feel a bit unresponsive due to the fact that the browser manages scrolling in a different thread and just periodically updates JS of the current position. (This is what sometimes leads to empty space at the bottom or top of a grid while you're scrolling.) The best solution I've been able to come up with for this- after a lot of thought and also discussion with others- is the overscan property.

I don't think I'm going to be able to support this feature, at least not in the near future. As such I'm going to close this issue. (It helps me with maintenance if I don't keep issues open that I don't plan to act on in the near future.)

I would be happy to consider a PR if you'd like to contribute towards adding this functionality. I don't think that deferring the onScroll callback is a route I should take because it adds latency to existing, simple users of that event. Exposing a public method to calculate the visible indices isn't a straight forward matter either as calling it before the updated render cycle would yield stale results (as state would contain stale data).

I _could_ cache some properties on the instance (not in state but just as instance properties) but I have a gut feeling that might lead to tricky edge-cases since we'd be doing calculations on potentially stale data (props) mixed with fresh data (cached "state").

Anyway, as I said. Going to close this as unsupported / out-of-scope for the time being. We can talk more if you have ideas though.

Was this page helpful?
0 / 5 - 0 ratings