Here is the codesandbox for this question: https://codesandbox.io/s/rdg-grouping-81b1s
I am using React-Data-Grid
to render a table. I render a ReactDataGrid
with two columns, and When you click on the text GROUP
in a header cell you group by that column.
To be able to have a custom header cell with that text GROUP
, I use the property headerRenderer
in the object defining the columns.
The value passed to this property is a function that takes an onClick
handler as parameter, and returns a functional React component that uses that onClick
handler.
The onClick
parameter is just a method on the original React component, and it is bound in the component's constructor.
As you can see, I am using this headerRenderer
property twice, once for each column. However, for the first column, I bind the parameter function to the React component again. For the second column I do not, and this generates an error when I try to click the GROUP
text for this column. See error image further below.
My question is: why do I have to bind given that I've already bound the function in the constructor?
import React from 'react';
import './App.css';
import ReactDataGrid from 'react-data-grid';
import { Data } from 'react-data-grid-addons';
const HeaderRowRenderer = function(props) {
return (
<div
style={{
backgroundColor: 'red',
paddingLeft: 10,
height: '100%',
padding: 0,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
<span>{props.column.name}</span>
<span onClick={props.onClick}>GROUP</span>
</div>
);
};
const HeaderRenderer = function(groupBy, onClick) {
return function(props) {
return (
<HeaderRowRenderer
{...props}
onClick={function() {
onClick(groupBy);
}}
/>
);
};
};
const rows = [{ productname: 'Beef', quantity: 5 }, { productname: 'Veggies', quantity: 10 }];
class App extends React.Component {
columns = [
{
key: 'productname',
name: 'Product',
width: 200,
headerRenderer: HeaderRenderer('productname', this.groupBy.bind(this)),
},
{
key: 'quantity',
name: 'Quantity',
headerRenderer: HeaderRenderer('quantity', this.groupBy),
},
];
constructor(props) {
super(props);
this.state = {
groupBy: new Set([]),
};
this.groupBy = this.groupBy.bind(this);
}
groupBy(group) {
const newSet = new Set(this.state.groupBy);
if (newSet.has(group)) {
newSet.delete(group);
} else {
newSet.add(group);
}
this.setState({ groupBy: newSet });
}
render() {
const groupBy = Array.from(this.state.groupBy);
// const rows = this.props.orderItems;
const groupedRows = Data.Selectors.getRows({
rows: rows,
groupBy,
});
return (
<div>
<ReactDataGrid
columns={this.columns}
rowGetter={i => groupedRows[i]}
rowsCount={groupedRows.length}
minHeight={650}
/>
</div>
);
}
}
export default App;
I looked at the code for React-Data-Grid
, and I believe that the headerRenderer
prop is called as below:
getCell() {
const { height, column, rowType } = this.props;
const renderer = this.props.renderer || SimpleCellRenderer;
if (isElement(renderer)) {
// if it is a string, it's an HTML element, and column is not a valid property, so only pass height
if (typeof renderer.type === 'string') {
return React.cloneElement(renderer, { height });
}
return React.cloneElement(renderer, { column, height });
}
return React.createElement(renderer, { column, rowType });
}
I'm not very familiar with the ways in which a function that was bound using bind
and then is passed around can lose this boundedness. Does this happen as a result of React.cloneElement, or what could be the cause of it?
state changed!
` for, etc. There's still a lot of code here that has nothing to do with the problem you're asking about. (mcve's usually require removing all semblance of what your real code does, and purely drilling down to the one thing that's not working for you) – Mike 'Pomax' Kamermans Jul 10 '19 at 21:45