react-tiny-virtual-list icon indicating copy to clipboard operation
react-tiny-virtual-list copied to clipboard

setState in onItemsRendered

Open maxsalven opened this issue 7 years ago • 1 comments

I need to keep track of which items are visible outside of the VirtualList component. However, if I call setState in onItemsRendered, then React will correctly complain:

Warning: Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.

Is there are correct pattern for this? Ideally VirtualList would have a renderProp style prop that could look like ({ RenderedListNode, startIndex, endIndex}) => Node.

This is the code, it works in this simple example but causes the React warning and issues in more complicated code:

// @flow

import React from "react";
import VirtualList from "react-tiny-virtual-list";

const data = Array(1000)
  .fill(0)
  .map((item, index) => index);

type Props = {};

type State = {
  currentlyVisibleIndex: number,
};

class Test extends React.Component<Props, State> {
  state = { currentlyVisibleIndex: 0 };

  onItemsRendered = ({ startIndex, stopIndex }) => {
    const { currentlyVisibleIndex } = this.state;
    if (currentlyVisibleIndex !== startIndex) {
      this.setState({ currentlyVisibleIndex: startIndex });
    }
  };

  render() {
    const { currentlyVisibleIndex } = this.state;

    return (
      <div>
        <div>Currently Visible: {currentlyVisibleIndex}</div>
        <VirtualList
          width="100%"
          height={600}
          itemCount={data.length}
          itemSize={50}
          overscanCount={0}
          renderItem={({ index, style }) => (
            <div key={index} style={style}>
              {data[index]}, Row: #{index}
            </div>
          )}
          onItemsRendered={this.onItemsRendered}
        />
      </div>
    );
  }
}

export default Test;

maxsalven avatar Jul 07 '18 11:07 maxsalven

I just setState within a setTimeout of 1ms to solve this.

charleskoehl avatar Dec 16 '18 19:12 charleskoehl