No Preview

Sorry, but you either have no stories or none are selected somehow.

If the problem persists, check the browser console, or the terminal you've run Storybook from.

Optimizing for Performance and Caveats

Pre-optimizaton can be the root of all evil, however, there are some best practices you can adhere to that will ensure React Data Table is giving you the best possible performance.

Passing non-primitive props (objects, arrays and functions)

While React Data Table has internal optimizations to try and prevent re-renders on deeper internal components, it's up to you to make sure that you understand how React manages rendering when props/state change as well as how JavaScript determines equality for non-primitives. As a general rule, or if you are experiencing performance issues you should ensure that any non-primitive props passed into React Data Table are not re-created on every render cycle. This is ever important when you have larger data sets or you are passing complex components and columns to DataTable.

Optimizing Class Components

You can typically achieve this by moving props such as objects, arrays, functions or other React components that you pass to React Data Table outside of the render method. For cases where you need to memoize memoize-one is a great library.

Examples of Optimizations

The following component will cause React Data Table to fully re-render every time onSelectedRowsChange is triggered. Why? Because when setState is called it triggers myComponent to re-render which by design triggers a re-render on all child components i.e. DataTable. But luckily for you React optimally handles this decision on when and how to re-render DataTable and a full re-render should not occur as long as DataTable props are the same.

However, in the example below columns changes on every re-render because it's being re-created. This is due to referential equality checking, simply: columns[] !== columns[]. In other words, while both instances of columns contain the same elements, they are "different" arrays.

Bad

... import React, { Component } from 'react'; import DataTable from 'react-data-table'; class MyComponent extends Component { updateState = state => { this.setState({ selectedRows: state.selectedRows }); // triggers MyComponent to re-render with new state } render () { // by design runs on every setState trigger // upon re-render columns array is recreated and thus causes DataTable to re-render const columns = [....]; return ( <DataTable data={data} columns={columns} onSelectedRowsChange={this.updateState} selectableRows /> ) } }

A "solution" could be to declare any field that is a non primitive field outside of the render function so that it does not get recreated on every re-render cycle:

Good

... import React, { Component } from 'react'; import DataTable from 'react-data-table'; const columns = [....]; // is only created once class MyComponent extends Component { updateState = state => { this.setState({ selectedRows: state.selectedRows }); } render () { return ( <DataTable data={data} columns={columns} onSelectedRowsChange={this.updateState} selectableRows /> ) } }

But that only works if you don't need to pass component props/methods to the column object. For example, what if you want to attach an event handler to a button in the row using column.cell?

const columns = [ { cell: () => <Button raised primary onClick={this.handleAction}>Action</Button>, ignoreRowClick: true, allowOverflow: true, button: true, }, ... ];

So how do we attach event handlers to our columns without having to place it in the render method and dealing with unnecessary re-renders?

  1. Create a columns function and pass the arguments needed
  2. Memoize the columns function

This way, when React checks if columns has changed columns will instead be the cached result (remember referential equality), thus no unnecessary re-render.

Got it? Let's try this again with the optimal solution using the wonderful memoization library memoize-one:

import React, { Component } from 'react'; import memoize from 'memoize-one'; import DataTable from 'react-data-table'; const columns = memoize(handleAction => [ ... { cell: () => <Button raised primary onClick={handleAction}>Action</Button>, ignoreRowClick: true, allowOverflow: true, button: true, }, ... ]); class MyComponent extends Component { updateState = state => { this.setState({ selectedRows: state.selectedRows }); } render () { return ( <DataTable data={data} columns={columns(this.updateState)} onSelectedRowsChange={this.updateState} selectableRows /> ); } }

Notice that this.updateState does not require memoization. That's because this.updateState is defined as a class method and therefore only created once.

Optimizing Functional/Hook Components

Optimizing Hook based components is much easier (or at least much less code). If you're building functional components in React 16.8+ you get access to React Hooks such as useMemo and useCallback. In this example, simply wrap columns in a useMemo callback and your updateState into useCallback:

import React, { useState, useMemo } from 'react'; import DataTable from 'react-data-table'; function MyComponentHook() { const [thing, setThing] = useState(); const handleAction = value => setThing(value); // unlike class methods updateState will be re-created on each render pass, therefore, make sure that callbacks passed to onSelectedRowsChange are memoized using useCallback const updateState = useCallback(state => console.log(state), []); // useMemo will only be created once const columns = useMemo(() => [ ... { cell: () => <Button raised primary onClick={handleAction}>Action</Button>, ignoreRowClick: true, allowOverflow: true, button: true, }, ... ], []); return ( <DataTable data={data} columns={columns} onSelectedRowsChange={updateState} selectableRows /> ); }