Detalhes do pacote

reactabular-virtualized

reactabular5.6kMIT8.18.0

Table virtualization for Reactabular

react, reactjs, table, tables

readme (leia-me)

reactabular-virtualized works in conjunction with reactabular-sticky and provides virtualization. The idea is that instead of rendering all table cells, it renders only ones visible at the viewport. This improves performance significantly with larger datasets.

If you want extra logging during development, set window.LOG_VIRTUALIZED = true at console.

Example:

/*
import React from 'react';
import * as Sticky from 'reactabular-sticky';
import * as Virtualized from 'reactabular-virtualized';
import * as resolve from 'table-resolver';

import { generateRows } from './helpers';
*/

const columns = [
  {
    property: 'id',
    props: {
      style: { minWidth: 50 }
    },
    header: {
      label: 'Index'
    },
    cell: {
      formatters: [
        (value, { rowIndex }) => <span>{rowIndex}</span>
      ]
    }
  },
  {
    property: 'name',
    props: {
      style: { minWidth: 300 }
    },
    header: {
      label: 'Name'
    }
  },
  {
    property: 'age',
    props: {
      style: { minWidth: 100 }
    },
    header: {
      label: 'Age'
    }
  },
  {
    property: 'company',
    props: {
      style: { minWidth: 400 }
    },
    header: {
      label: 'Company'
    }
  },
  {
    property: 'product',
    props: {
      style: { minWidth: 400 }
    },
    header: {
      label: 'Product'
    }
  }
];

const schema = {
  type: 'object',
  properties: {
    id: {
      type: 'string'
    },
    name: {
      type: 'string'
    },
    product: {
      type: 'string'
    },
    company: {
      type: 'string'
    },
    age: {
      type: 'integer'
    }
  },
  required: ['id', 'name', 'product', 'company', 'age']
};
// Resolving indices is an optional step. You can skip it if you don't
// rely on rowIndex anywhere. But if you do, it's good to calculate and
// include to the data. Reactabular's rendering logic is able to pick it
// up by convention (`_index` field).
const rows = resolve.resolve({ columns })(generateRows(1000, schema));

class VirtualizedTable extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      rows,
      columns
    };

    this.tableHeader = null;
    this.tableBody = null;
  }
  componentDidMount() {
    // We have refs now. Force update to get those to Header/Body.
    this.forceUpdate();
  }
  render() {
    return (
      <div>
        <div>
          <label>Scroll to index: </label>
          <input
            type="text"
            onChange={e => this.tableBody.scrollTo(e.target.value)}
          />
        </div>

        <Table.Provider
          className="pure-table pure-table-striped"
          columns={columns}
          renderers={{
            body: {
              wrapper: Virtualized.BodyWrapper,
              row: Virtualized.BodyRow
            }
          }}
        >
          <Sticky.Header
            style={{
              maxWidth: 800
            }}
            ref={tableHeader => {
              this.tableHeader = tableHeader && tableHeader.getRef();
            }}
            tableBody={this.tableBody}
          />

          <Virtualized.Body
            rows={rows}
            rowKey="id"
            style={{
              maxWidth: 800,
              maxHeight: 400
            }}
            height={400}
            ref={tableBody => {
              this.tableBody = tableBody && tableBody.getRef();
            }}
            tableHeader={this.tableHeader}
          />
        </Table.Provider>
      </div>
    );
  }
}

<VirtualizedTable />

Scrolling within a container

By passing in a function as container which returns a reference to a container to Virtualized.Body, you can use the scrollbar of a surrounding element as the scroll for virtualization. This might be useful if you want to render multiple containers in the same scrolling area, or if you want the table to scroll along with the rest of your page.

/*
import React from 'react';
import * as Sticky from 'reactabular-sticky';
import * as Virtualized from 'reactabular-virtualized';
import * as resolve from 'table-resolver';

import { generateRows } from './helpers';
*/

const columns = [
  {
    property: 'id',
    props: {
      style: { minWidth: 50 }
    },
    header: {
      label: 'Index'
    },
    cell: {
      formatters: [
        (value, { rowIndex }) => <span>{rowIndex}</span>
      ]
    }
  },
  {
    property: 'name',
    props: {
      style: { minWidth: 300 }
    },
    header: {
      label: 'Name'
    }
  },
  {
    property: 'age',
    props: {
      style: { minWidth: 100 }
    },
    header: {
      label: 'Age'
    }
  },
  {
    property: 'company',
    props: {
      style: { minWidth: 400 }
    },
    header: {
      label: 'Company'
    }
  },
  {
    property: 'product',
    props: {
      style: { minWidth: 400 }
    },
    header: {
      label: 'Product'
    }
  }
];

const schema = {
  type: 'object',
  properties: {
    id: {
      type: 'string'
    },
    name: {
      type: 'string'
    },
    product: {
      type: 'string'
    },
    company: {
      type: 'string'
    },
    age: {
      type: 'integer'
    }
  },
  required: ['id', 'name', 'product', 'company', 'age']
};
// Resolving indices is an optional step. You can skip it if you don't
// rely on rowIndex anywhere. But if you do, it's good to calculate and
// include to the data. Reactabular's rendering logic is able to pick it
// up by convention (`_index` field).
const rows = resolve.resolve({ columns })(generateRows(1000, schema));

class VirtualizedTable extends React.Component {
  render() {
    return (
      <div>
       <div ref={(ref) => this.container = ref} style={{ height: '500px', overflow: 'auto' }}>
            {([1, 2, 3]).map(count => 
            <Table.Provider
              key={count}
              className="pure-table pure-table-striped"
              columns={columns}
              style={{ margin: '20px', }}
              renderers={{
                body: {
                  wrapper: Virtualized.BodyWrapper,
                  row: Virtualized.BodyRow
                }
              }}
            >
              <Table.Header
                style={{
                  maxWidth: 800
                }}
              />

              <Virtualized.Body
                container={() => this.container}
                rows={rows}
                rowKey="id"
                style={{
                  maxWidth: 800
                }}
                height={400}
              />
            </Table.Provider>
            )}
        </div>
      </div>
    );
  }
}

<VirtualizedTable />

Scrolling to Index

Virtualized.Body ref exposes scrollTo method for scrolling through index. If you want to scroll based on some field value, search the dataset first and pass the resulting index here.

Define the Height of Table

Please note height of <Virtualized.Body> must be defined. If height is not defined, style.maxHeight will be used. In below example, we use style.maxHeight instead of height,

/*
import React from 'react';
import * as Sticky from 'reactabular-sticky';
import * as Virtualized from 'reactabular-virtualized';

import { generateRows } from './helpers';
*/

const columns = [
  {
    property: 'id',
    props: {
      style: { minWidth: 350 }
    },
    header: {
      label: 'Index'
    }
  },
  {
    property: 'name',
    props: {
      style: { minWidth: 300 }
    },
    header: {
      label: 'Name'
    }
  }
];
const schema = {
  type: 'object',
  properties: {
    id: {
      type: 'string'
    },
    name: {
      type: 'string'
    }
  },
  required: ['id', 'name']
};
const rows = generateRows(1000, schema);

class VirtualizedTable extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      rows,
      columns
    };

    this.tableHeader = null;
    this.tableBody = null;
  }
  componentDidMount() {
    // We have refs now. Force update to get those to Header/Body.
    this.forceUpdate();
  }
  render() {
    return (
      <div>
        <Table.Provider
          className="pure-table pure-table-striped"
          columns={columns}
          renderers={{
            body: {
              wrapper: Virtualized.BodyWrapper,
              row: Virtualized.BodyRow
            }
          }}
        >
          <Sticky.Header
            style={{
              maxWidth: 800
            }}
            ref={tableHeader => {
              this.tableHeader = tableHeader && tableHeader.getRef();
            }}
            tableBody={this.tableBody}
          />

          <Virtualized.Body
            rows={rows}
            rowKey="id"
            style={{
              maxWidth: 800,
              maxHeight: 400
            }}
            ref={tableBody => {
              this.tableBody = tableBody && tableBody.getRef();
            }}
            tableHeader={this.tableHeader}
          />
        </Table.Provider>
      </div>
    );
  }
}

<VirtualizedTable />

Using relative column widths

You can define column widths as percentages of the table's width, like so:

const columns = [
  {
    property: 'id',
    props: {
      style: { width: "35%" }
    },
    ...

To force rows to stretch to the full width of the tbody container, however, a flex-based styling workaround is required. This StackOverflow answer suggests the configuration below. If this does not work for you, due to other styling constraints or concerns about browser compatibility, you may consider the other answers posted there, or you may need to take care of your column sizing and resizing in JavaScript.

{
  display: flex;
  flex-flow: column;

  thead,
  tbody tr {
    display: table;
    table-layout: fixed;
  }

  thead {
    flex: 0 0 auto;
    width: 100%;
    background: #eaeaea;
    tr {
      width: calc(100% - 0.9em); /* 0.9em approximates scrollbar width */
      display: table;
    }
  }

  tbody {
    display: block;
    flex: 1 1 auto;
    overflow-y: scroll;

    tr {
      width: 100%;
    }
  }
}

changelog (log de mudanças)

8.17.0 / 2019-01-21

  • Fix - Fix virtualized scrolling in container to account for thead height. #361

8.16.0 / 2018-10-01

  • Fix - scrollTo works correctly now. #359
  • Refactor - Reuse math internally better.

8.15.0 / 2018-09-04

  • Feature - Added option to use a container for the scrolling in virtualization. #356

8.12.1 / 2018-03-01

  • Bug fix - Check if window is defined before checking LOG_VIRTUALIZED. #337

8.12.0 / 2017-10-05

  • Chore - Support React 16. #324

8.11.0 / 2017-09-25

  • Bug fix - Clear setTimeout timer on componentWillUnmount to avoid warnings (good practice anyway). #320

8.7.0 / 2017-02-02

  • Feature - Pick up props.style.maxHeight at Virtualized.Body if it's set. #277

8.6.0 / 2017-01-16

  • Bug fix - Bump lodash peer dependency to v4 minimum. This was expected already, but the version was wrong.

8.5.1 / 2017-01-12

  • Bug fix - Calculate rows when height changes. #270

8.0.0 / 2016-11-27

  • Bug fix - Improve horizontal scrolling performance when used with reactabular-sticky. If it detects Y didn't change while scrolling, it skips rendering now.
  • Bug fix - Skip functions at BodyRow shouldComponentUpdate.
  • Breaking - Speed up vertical scrolling by implementing shouldComponentUpdate for rows. Now it detects whether or not a row has been measured and also does check based on column and row changes like default SCU at reactabular-table.

6.0.3 / 2016-10-19

  • Bug fix - Bump peer version ranges to avoid npm warnings.

6.0.0 / 2016-10-14

  • Feature - Add scrollTo(index) method to Virtualized.Body ref.

5.0.2 / 2016-09-28

  • Bug fix - Skip setState on componentWillReceiveProps if no rows were calculated. #209

3.0.6 / 2016-09-12

  • Bug fix - Rework initial measurement so that it works with CSS solutions like Radium.

3.0.2 / 2016-09-01

  • Feature - Push development logging behind window.LOG_VIRTUALIZED.

3.0.1 / 2016-09-01

  • Bug fix - Keep header and body in sync when scrolling at header.

3.0.0 / 2016-09-01

  • Initial release.