Code Monkey home page Code Monkey logo

react-base-table's Introduction

react-base-table

BaseTable is a react table component to display large datasets with high performance and flexibility

Install

# npm
npm install react-base-table --save

# yarn
yarn add react-base-table

Usage

import BaseTable, { Column } from 'react-base-table'
import 'react-base-table/styles.css'
// Important: if you fail to import react-base-table/styles.css then 
// BaseTable will not render as advertised in the included examples.
// For advanced styling see link below:
// https://github.com/Autodesk/react-base-table#advance
 ...
<BaseTable data={data} width={600} height={400}>
  <Column key="col0" dataKey="col0" width={100} />
  <Column key="col1" dataKey="col1" width={100} />
  ...
</BaseTable>
...

Learn more at the website

unique key

key is required for column definition or the column will be ignored

Make sure each item in data is unique by a key, the default key is id, you can customize it via rowKey

size

width is required for column definition, but in flex mode(fixed={false}), you can set width={0} and flexGrow={1} to achieve flexible column width, checkout the Flex Column example

width and height(or maxHeight) are required to display the table properly

In the examples we are using a wrapper const Table = props => <BaseTable width={700} height={400} {...props} /> to do that

If you want it responsive, you can use the AutoResizer to make the table fill the container, checkout the Auto Resize example

closure problem in custom renderers

In practice we tend to write inline functions for custom renderers, which would make shouldUpdateComponent always true as the inline function will create a new instance on every re-render, to avoid "unnecessary" re-renders, BaseTable ignores functions when comparing column definition by default, it works well in most cases before, but if we use external data instead of reference state in custom renderers, we always get the staled initial value although the data has changed

It's recommended to inject the external data in column definition to solve the problem, like <Column foo={foo} bar={bar} cellRenderer={({ column: { foo, bar }}) => { ... } } />, the column definition will update on external data change, with this pattern we can easily move the custom renderers out of column definition for sharing, the downside is it would bloat the column definition and bug prone

Things getting worse with the introduction of React hooks, we use primitive state instead of this.state, so it's easy to encounter the closure problem, but with React hooks, we can easily memoize functions via useCallback or useMemo, so the implicit optimization could be replaced with user land optimization which is more intuitive, to turn off the implicit optimization, set ignoreFunctionInColumnCompare to false which is introduced since v1.11.0

Here is an example to demonstrate

Browser Support

BaseTable is well tested on all modern browsers and IE11. You have to polyfill Array.prototype.findIndex to make it works on IE

The examples don't work on IE as they are powered by react-runner which is a react-live like library but only for modern browsers.

Advance

BaseTable is designed to be the base component to build your own complex table component

Styling

The simplest way is overriding the default styles (assuming you are using scss)

// override default variables for BaseTable
$table-prefix: AdvanceTable;

$table-font-size: 13px;
$table-padding-left: 15px;
$table-padding-right: 15px;
$column-padding: 7.5px;
...
$show-frozen-rows-shadow: false;
$show-frozen-columns-shadow: true;

@import '~react-base-table/es/_BaseTable.scss';

.#{$table-prefix} {
  &:not(.#{$table-prefix}--show-left-shadow) {
    .#{$table-prefix}__table-frozen-left {
      box-shadow: none;
    }
  }

  &:not(.#{$table-prefix}--show-right-shadow) {
    .#{$table-prefix}__table-frozen-right {
      box-shadow: none;
    }
  }

  ...
}

You can write your own styles from scratch or use CSS-in-JS solutions to achieve that

Custom components

<BaseTable
  classPrefix="AdvanceTable"
  components={{
    TableCell: AdvanceTableCell,
    TableHeaderCell: AdvanceTableHeaderCell,
    ExpandIcon: AdvanceExpandIcon,
    SortIndicator: AdvanceSortIndicator,
  }}
  ...
/>

Custom renderers & props

There are a lot of highly flexible props like xxxRenderer and xxxProps for you to build your own table component, please check the api and examples for more details

Example

We are using a advanced table component based on BaseTable internally, with much more features, including row selection, row grouping, data aggregation, column settings, column reordering, and column grouping, tooltip, inline editing.

AdvanceTable

In real products

Development

We use Yarn as the package manager, checkout this repo and run yarn under both root folder and website folder in install packages, then run yarn start to start the demo site powered by Gatsby

Contributing

Please check guidelines for more details

react-base-table's People

Contributors

dependabot[bot] avatar ekazim avatar gjthompson1 avatar jamesonhill avatar janlaywss avatar nickytonline avatar nihgwu avatar ricklucassen avatar steven-qi avatar tonnyskk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-base-table's Issues

The expandIconProps function not be called when forceUpdateTable

I custom expandIconProps to control the expand icon is loading or not .
I changed the component state like loadingKes and call the api forceUpdateTable, the expandIconProps not be called anymore , i also change the datasource ,still.

code source:

image

look like this :

TEST

input box in the inline editor lose focus and state on change

In case when we use input box in the Inline Editing, we lose focus and component state at the first value change in text box, gif file with example and code you can find below

bug

const { Overlay } = ReactOverlays

const CellContainer = styled.div`
  display: flex;
  flex: 1 0 100%;
  align-items: center;
  height: 100%;
  width: 100%;
  overflow: hidden;
  margin: 0 -5px;
  padding: 5px;
  border: 1px dashed transparent;
`

const GlobalStyle = createGlobalStyle`
  .BaseTable__row:hover,
  .BaseTable__row--hover {
    ${CellContainer} {
      border: 1px dashed #ccc;
    }
  }
`

const Select = styled.select`
  width: 100%;
  height: 30px;
  margin-top: 10px;
`

class EditableCell extends React.PureComponent {
  state = {
    value: this.props.cellData,
    editing: false,
  }

  setTargetRef = ref => (this.targetRef = ref)

  getTargetRef = () => this.targetRef

  handleClick = () => this.setState({ editing: true })

  handleHide = () => this.setState({ editing: false })

  handleChange = e =>
    this.setState({
      value: e.target.value,
      editing: false,
    })

  render() {
    const { container, rowIndex, columnIndex } = this.props
    const { value, editing, cellData } = this.state


    return (
      <CellContainer ref={this.setTargetRef} onClick={this.handleClick}>
        {!editing && value}
        {editing && this.targetRef && (
          <Overlay
            show
            flip
            rootClose
            container={container}
            target={this.getTargetRef}
            onHide={this.handleHide}
          >
            {({ props, placement }) => (
              <div
                {...props}
                style={{
                  ...props.style,
                  width: this.targetRef.offsetWidth,
                  top:
                    placement === 'top'
                      ? this.targetRef.offsetHeight
                      : -this.targetRef.offsetHeight,
                }}
              >
                <input type="text"  value={value} onChange={this.handleChange} />
              </div>
            )}
          </Overlay>
        )}
      </CellContainer>
    )
  }
}

const columns = generateColumns(2)
const data = generateData(columns, 10)

columns[0].cellRenderer = EditableCell
columns[0].width = 300

export default () => (
  <>
    <GlobalStyle />
    <Table fixed columns={columns} data={data} />
  </>
)

auto generate row id

Is it possible to set the component to autogenerate the row id and have the component generate this key on its own, like 1,2,3,4,5?

Consider Adding an onEndColumnResize prop to <BaseTable />

We're starting to use react-base-table on Shotgun. One of the things we're working on is saving column sizes after resizing them. We have this functionality in our current grid, but need to port this functionality to our new grid that is using <BaseTable />. The BaseTable component has an onColumnResize prop, but in our case, we really only want to save settings once the column is finished resizing. I have a PR that adds an onEndColumnResize prop to <BaseTable /> for columns that are resizable.

Is this something you would consider adding to <BaseTable />?

ColumnResizer indicator line incorrect

The resizer indicator line position will be incorrect when using right frozen columns and drag too much.

gif below:

TEST

BTW. How to custom resizer indicator style , something like width 、maxWidth

Expand lag in develop env

Expand lag in develop env but not appear in production mode .It cost about 20 seconds when i expand a row in 10000 rows table.

fluid column width

Right now I'm always passing a width to every column, if I don't pass, I couldn't see it on table.

I think we can just have a prop called defaultColumnWidth then we can just use it while we're calculating column width.

  getColumnWidth(column, key) {
    const {
      isFluid,
      defaultColumnWidth,
      initialColumnWidths,
    } = this.props;
    const baseWidth = 20;

    if (isFluid) {
      return initialColumnWidths[column.key] || column.width || (baseWidth + (column.title.length * 10));
    }

    return initialColumnWidths[column.key] || column.width || defaultColumnWidth;
  }

this function will gonna make a variable called calculatedColumns after aggregating all columns. We can use it inside this functionality:

export function adjustColumnWidths(calculatedColumns, calculatedColumnsWidth, expectedWidth) {
  if (expectedWidth > totalWidth) {
    return distributeWidth(columns, expectedWidth - calculatedColumnsWidth);
  }
  return columns;
}

function distributeWidth(columns, _remainingWidth) {
  const newColumns = [];
  let remainingWidth = _remainingWidth;
  const perColumnWidth = remainingWidth / columns.length;

  columns.forEach(column => {
    const newColumnWidth = Math.floor(column.width + perColumnWidth);
    remainingWidth -= perColumnWidth;
    newColumns.push({
      ...column,
      width: newColumnWidth,
    });
  });

  return newColumns;
}

This whole functionality will give us a chance to pass columns without width key.

In my project, we've a toggle column feature and sometimes we're showing only 1 or 2 columns, it would be nice to have this fluid functionality to spread them into whole table.

rowID could be number too?

I know rowID as number is not scalable but some of our data will not gonna be bigger to put as string. yep, in some cases our rowID is just number, I don't want to aggregate my data and make them string for this case, it would be nice to accept number and string for rowID propType.

hoveredRowKey: PropTypes.string,

scrollToRow broken in 1.7.0

As of version 1.7.0 scrollToRow no longer works.

The issue seems to be the scrollToLeft statement that was added last in the scrollToRow function.

This statement resets the horizontal scrolling position to what it was before the method was called.

Custom Table and Column

Hey guys, I'm trying to write a wrapper for Table and Column, but I don't know what's wrong.

This is my Table component wrapper:
image

This is my Column component wrapper:
image

This is where I'm using it:
image

This is how it's being rendered:
image

This is how it should be rendered:
image

The weird part is that the console.log on Column component is not printing anything.

Am I doing anything wrong? This is the right way to do this?

Thank you,

Rod

Custom Column

I am trying to define a custom Column component with selection functionality but the cellRenderer and headerRenderer props do not seem to use the custom components I've defined in the file when I import the Column to use.

Example can be found here: https://codesandbox.io/s/checkboxcolumnexample-rkpjt

I am on "react-base-table": "1.6.5"

emptyRenderer does not seem to work with maxHeight

It appears that when using maxHeight with emptyRenderer, it does not actually use emptyRenderer.

I created this sandbox to replicate the issue. Not sure if I should be setting height if data.length === 0?

Basically, I was trying to have render only up to a certain height, but if no rows are available to then render a message such as "No Data". Thanks in advance!

Spreadsheet like editing

This looks like an amazing project with great performance. Congratulations! I wanted to ask: Are there any plans to add spreadsheet like functionality for making all cells editable?

problem with scrollbar size

hi, we're always showing scrollbar inside our tables and right now if there's no mouse plugged to the computer, our gridtables height computation looks problematic.

If could be a change to add a prop for this? like defaultScrollbarSize? cause I don't see any other solution to make getScrollbarSize util get this size always.

Make the custom expand icon easier ?

I want to custom the expand icon styles , but i found it is very difficult. Because when i use the
table components to reset expandIcon component ,i have to handle the onExpand event.
I just want to set the expand icon display styles, only use css or custom component easily.

Trying to use react hook within cellRenderer is not allowed.

I was trying to use a react-apollo-hook in a custom cellRenderer in order to load data into a modal if the user clicks. However, I get the error message: Invalid hook call: Hooks can only be called inside of the body of a function component.

I believe it is because of the way cellRenderer is being called here.

Is there a different way to accomplish this. Or is using hooks in a cell outside of the scope of this project? Thanks for the help in advance.

For example I was trying to do something like this:

import React from 'react'
import PropTypes from 'prop-types'
import { useLazyQuery } from '@apollo/react-hooks'
import { get } from 'lodash'

import { QUERY } from './queries'

export const InterpretationsCell = ({ cellData,  }) => {

  const [loadDetails, { loading, data }] = useLazyQuery(QUERY)

  ...do something
  
  return <p>{cellData}</p>
}

InterpretationsCell.propTypes = {
  column: PropTypes.shape({
    variantType: PropTypes.string.isRequired,
    idKey: PropTypes.string.isRequired,
  }).isRequired,
}

export default InterpretationsCell

Roadmap for V2.0

Here is the wishlist I'd like to have for the next major version:

  • Don't use Grid for table header
  • Replace react-virtualized with react-window #12
  • remove deprecated lifecycles #10
  • Dynamic row heights #170
  • Make virtualization configurable
  • A11y
  • UT
  • plugin support
  • rewrite with TypeScript
  • support custom children key

Breaking changes:

  • use rollup to bundle package
  • omit placeholders in rowRenderer
  • rename tagName to as or elementType
  • rename scrollToPosition to scrollTo
  • rename headerRenderer to headerRowRenderer
  • rename headerRenderer for Column to headerCellRenderer
  • move AutoResizer to a separate package

Nice to have:

  • better size calculation to support cell with borders #149

title: reactElement or headRenerer: reactElement will cause a stockoverflow

I have code like below

{
      key: 'sectorName',
      dataKey: 'sectorName',
      width: 100,
      title: <MyComponent {...someProps}>,
      frozen: Column.FrozenDirection.LEFT,
    }

this will cause a stack overflow, because in the source code

 if (!isObjectEqual(nextColumns, columns) || nextProps.fixed !== this.props.fixed) {
      this.columnManager.reset(nextColumns, nextProps.fixed);
  }

the isObjectEqual will throw an error, is this a bug? because I want to render a component in my header cell

Question : roweventhandlers, do you have working example beside in the website ?

Hi, basead on the example I added rowEventHandlers with console.log and it only run when the page is loaded, and nothing happened when row is clicked

const rowEventHandlers = {
    onClick: console.log('clicked'),
    
  }
...
<BaseTable ... rowEventHandlers={rowEventHandlers} />

And based on your example

const rowEventHandlers = {
  onClick: action('click'),
  onDoubleClick: action('double click'),
  onContextMenu: action('context menu'),
  onMouseEnter: action('mouse enter'),
  onMouseLeave: action('mouse leave'),
}

How to get the event, because it only passed string ?

Thanks

Dragable Row

Dragable Row example resets data order on drag end.

rowspan supported?

does row span is supported? I find the clospan is supported in the example.

headerRenderer will execute multiple times when the columns has frozen: 'left' and frozen: 'right'

As the title mentioned, when I have a table and the columns not only contains the left frozen columns, but also the right frozen columns, because I want to merge some columns in header, like this example https://autodesk.github.io/react-base-table/examples/multi-header, so I need implement the callback headerRenderer, but this callback will be called 3 times, and there is no indicator which is left table main table, and right table, in user's (developer who use this component) view, I think this function will be called one time only, because there is only one header.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.