2017-08-15 14 views
0

我使用反应虚拟化构建无限装载网格,它也使用AutoSizer来处理动态网格宽度和WindowScroller以使得能够与视口滚动触发loadMoreRows。但是,我无法在我的无限加载Grid的适当位置成功触发loadMoreRows无限装载网格是在错误的时间

我已经缩小了两两件事:

  • 当我设置columnCount 1而不是3下面的示例所示,装载过程似乎按预期方式工作(即您滚动接近底部,它会加载另一批次,直到我们完全加载上一批为止,它才会再次加载)。

  • 累积了大约40行(在演示顶部显示)之后,除非向上滚动到上一行,否则无法触发loadMoreRows()。要重现此行为,请向下滚动,直到网格停止在网格底部加载新项目。然后尝试向上滚动,然后再次向下滚动,以查看它如何在网格内的某个位置触发loadMoreRows()

我把一个最小的plunker演示这将使随机的“Lorem存有”文本片段的3列网格。这个示例内容没有终点,它只会像滚动一样加载。

Plunker演示:http://plnkr.co/edit/uoRdanlB1rXsgBe2Ej8i

import React, { Component } from 'react'; 
import { render } from 'react-dom'; 
import { AutoSizer, CellMeasurer, CellMeasurerCache, Grid, InfiniteLoader, WindowScroller } from 'react-virtualized'; 

const MIN_BATCH_SIZE = 40; 

// Return random snippet of lorem ipsum text 
const randText =() => { 
    const text = [ 
     'Lorem ipsum dolor sit amet.', 
     'Consectetur adipisicing elit.', 
     'Lorem ipsum dolor sit amet, consectetur adipisicing elit.', 
     'Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 
     'Ut enim ad minim veniam.', 
     'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', 
     'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.', 
     'Excepteur sint occaecat cupidatat non proident.', 
     'Sunt in culpa qui officia deserunt mollit anim id est laborum.', 
     'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', 
     'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.' 
    ]; 

    return text[Math.floor(Math.random() * text.length)]; 
}; 

// Cell data 
const list = []; 


// ----------------------------------------------------------------------------- 


// Infinite loading Grid that is AutoSize'd and WindowScroll'd with dynamic cell heights 
class App extends Component { 
    constructor(props) { 
     super(props); 

     this.state = { 
      columnWidth: 300, 
      columnCount: 3, 
      rowCount: 0, 
      isLoading: false 
     }; 

     this._cache = new CellMeasurerCache({ 
      fixedWidth: true, 
      defaultHeight: 30 
     }); 

     this._cellRenderer = this._cellRenderer.bind(this); 
     this._isRowLoaded = this._isRowLoaded.bind(this); 
     this._loadMoreRows = this._loadMoreRows.bind(this); 
     this._onResize = this._onResize.bind(this); 
     this._onSectionRendered = this._onSectionRendered.bind(this); 
    } 

    componentDidMount() { 
     this.setState({ rowCount: 1 }); 
    } 

    componentWillUpdate(nextProps, nextState) { 
     const { columnCount, rowCount } = this.state; 

     if (rowCount !== nextState.rowCount) { 
      if (nextState.rowCount > rowCount) { 
       // Re-measure the row at the index which was last occupied by "loading" content 
       for (let i = 0; i < columnCount; i++) { 
        this._cache.clear(this._lastLoadingIndex, i); 
       } 
      } 
     } 
    } 

    render() { 
     const { columnCount, columnWidth, rowCount } = this.state; 

     return (
      <div className="container-fluid"> 
       <h1 className="page-header lead">RV Infinite Grid</h1> 

       <InfiniteLoader 
        isRowLoaded={this._isRowLoaded} 
        loadMoreRows={this._loadMoreRows} 
        rowCount={rowCount} 
        threshold={5} 
       > 
        {({ onRowsRendered, registerChild }) => { 
         this._onRowsRendered = onRowsRendered; 

         return (
          <WindowScroller> 
           {({ height, scrollTop }) => (
            <AutoSizer 
             disableHeight 
             onResize={this._onResize} 
            > 
             {({ width }) => (
              <Grid 
               autoHeight 
               width={width} 
               height={height} 
               scrollTop={scrollTop} 

               ref={grid => { 
                this._grid = grid; 
                registerChild(grid); 
               }} 

               columnWidth={columnWidth} 
               columnCount={columnCount} 

               rowCount={rowCount} 
               rowHeight={this._cache.rowHeight} 

               cellRenderer={this._cellRenderer} 
               onSectionRendered={this._onSectionRendered} 
              /> 
             )} 
            </AutoSizer> 
           )} 
          </WindowScroller> 
         ); 
        }} 
       </InfiniteLoader> 
      </div> 
     ); 
    } 

    _isRowLoaded({ index }) { 
     const { rowCount } = this.state; 

     return index < rowCount - 1; 
    } 

    _loadMoreRows({ startIndex, stopIndex }) { 
     const { isLoading } = this.state; 
     const delay = 100 + Math.floor(Math.random() * 3000); // random delay to simulate server response time 

     if (!isLoading) { 
      this.setState({ 
       isLoading: true 
      }); 

      setTimeout(() => { 
       // Generate some new rows (for this example, we have no actual end point) 
       for (let i = 0; i < MIN_BATCH_SIZE; i++) { 
        list.push([ randText(), randText(), randText() ]); 
       } 

       // Cancel the "loading" state and update the`rowCount` 
       this.setState({ 
        isLoading: false, 
        rowCount: list.length + 1 
       }, done); 
      }, delay); 

      let done; 
      return new Promise(resolve => done = resolve); 
     } 
    } 

    _cellRenderer({ key, rowIndex, columnIndex, parent, style }) { 
     const { columnCount, columnWidth, rowCount } = this.state; 
     let content; 

     // Render cell content 
     if (rowIndex < rowCount - 1) { 
      const cellStyle = Object.assign({}, style, { 
       backgroundColor: (rowIndex % 2 ? null : '#eee') 
      }); 

      content = (
       <div style={cellStyle}> 
        <div style={{ padding: '20px' }}> 
         {list[rowIndex][columnIndex] || <em className="text-muted">empty</em>} 
        </div> 
       </div> 
      ); 
     } 

     // Render "loading" content 
     else if (columnIndex === 0) { 
      // Remember this `index` so we can clear its measurements from the cache later 
      this._lastLoadingIndex = rowIndex; 

      const cellStyle = Object.assign({}, style, { 
       width: (columnWidth * columnCount), // Give loader the full grid width 
       textAlign: 'center' 
      }); 

      content = <div style={cellStyle}>Loading...</div>; 
     } 

     // Render empty cell (for incomplete rows) 
     else { 
      content = <div style={style} />; 
     } 

     return (
      <CellMeasurer 
       key={key} 
       cache={this._cache} 
       parent={parent} 
       columnIndex={columnIndex} 
       rowIndex={rowIndex} 
      > 
       {content} 
      </CellMeasurer> 
     ); 
    } 

    _onResize({ width }) { 
     this.setState({ 
      // Subtracting 30 from `width` to accommodate the padding from the Bootstrap container 
      columnWidth: (width - 30)/3 
     }); 

     this._cache.clearAll(); 
     this._grid.recomputeGridSize(); 
    } 

    _onSectionRendered({ columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex }) { 
     const { columnCount } = this.state; 

     const startIndex = rowStartIndex * columnCount + columnStartIndex; 
     const stopIndex = rowStopIndex * columnCount + columnStopIndex; 

     this._onRowsRendered({ 
      startIndex, 
      stopIndex 
     }); 
    } 
} 


render(<App />, document.getElementById('root')); 
+0

这行在你的'_loadMoreRows'函数中是错误的:'rowCount:Math.ceil(list.length/columnCount)+ 1'。它不符合组件其余部分的逻辑。它应该是:'rowCount:list.length + 1'。这里似乎还有其他的事情发生,但我还不确定它是什么。 – brianvaughn

+0

非常感谢@brianvaughn发现这个错误。我忘了更新,因为我正在调整我的真实应用程序到这个最小的例子。我更新了我的plunker演示,并修复了该行。确实还有一个问题。我会继续探索并尝试。谢谢:) – wavematt

+0

@brianvaughn我能回答我自己的问题。我向我的'onRowsRendered'函数提供了错误的行范围。 – wavematt

回答

0

回答我的问题...

事实证明,我的_onSectionRendered函数提供了错误的范围内,以我的_onRowsRendered功能。我承认我盲目地将InfiniteLoader docs中的示例代码片段复制并粘贴到我自己的项目中,直到我对其了解更多。对我来说,首先要按照它在文档中所做的方式返回单元格区域,直到我提醒自己InfiniteLoader正在查看行而不是单元格。

文档中的示例将startIndexstopIndex设置为一组单元格,而不是返回行的范围。

_onSectionRendered ({ columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex }) { 
    const startIndex = rowStartIndex * columnCount + columnStartIndex 
    const stopIndex = rowStopIndex * columnCount + columnStopIndex 

    this._onRowsRendered({ 
    startIndex, 
    stopIndex 
    }) 
} 

为了解决我的问题,我只有通过rowStartIndexrowStopIndexonRowsRendered()

onSectionRendered({ rowStartIndex, rowStopIndex }) { 
    this._onRowsRendered({ 
    startIndex: rowStartIndex, 
    stopIndex: rowStopIndex 
    }) 
} 

这在我的plunker example中更新。