Reputation: 2972
I've my implementation of fixed-data-table working with custom cell types.
My text cells may be edited and they contain State which only contains value property.
Then I've onBlur event that fires after the input loses focus and updates my data on the table state. All this works fine.
Expected Behavior / Current Behavior
However, when my data changes from pagination or sort events, my Cell's don't update the state with the new values, because I'm setting the state on the Constructor and it only runs once.
Steps to Reproduce (for bugs)
var Table = FixedDataTable.Table;
var Column = FixedDataTable.Column;
var Cell = FixedDataTable.Cell;
//Custom header cell
var MyHeaderCell = React.createClass({
mixins: [React.addons.PureRenderMixin],
render: function() {
return <Cell {...this.props}>Column: {this.props.columnKey}</Cell>;
}
})
//Custom cell
var MyCell = React.createClass({
mixins: [React.addons.PureRenderMixin],
getInitialState: function() {
return {
value: this.props.data[this.props.rowIndex][this.props.columnKey]
};
},
render: function() {
return <Cell {...this.props}>Cell: {this.state.value}</Cell>;
}
})
var MyTable = React.createClass({
mixins: [React.addons.PureRenderMixin],
render: function() {
var width = this.props.width;
var height = this.props.height;
var data = this.props.data;
return (
<Table
rowHeight={50}
rowsCount={data.length}
width={width}
height={height}
headerHeight={50}
>
{this.createColumns()}
</Table>
);
},
createColumns: function() {
var width = this.props.width;
var data = this.props.data;
var columnCount = data[0].length;
var columns = [];
for (let i = 0; i < columnCount; i++) {
columns.push(
<Column
key={i}
columnKey={i}
header={<MyHeaderCell />}
cell={<MyCell data={data} />}
width={width / columnCount}
/>
)
}
return columns;
}
})
var container = document.getElementById('container');
// Table data as a list of array.
var myData = [
['a1', 'b1', 'c1'],
['a2', 'b2', 'c2'],
['a3', 'b3', 'c3'],
// .... and more
];
function changeData() {
var temp = myData.slice();
debugger;
var iR = 0;
var newData = [
['x1', 'k1', 'w1'],
['x2', 'k2', 'w2'],
['x3', 'k3', 'w3'],
// .... and more
];
myData = newData;
render();
}
// Render your table
function render() {
var height = container.offsetHeight;
var width = container.offsetWidth;
ReactDOM.render(<div><button onClick={changeData}>Change Data</button><MyTable height={height} width={width} data={myData} /></div>,
document.getElementById('container'));
}
window.onresize = render;
render();
Click on ChangeData and nothing happens, but if you change the following code:
{this.state.value}
to
this.props.data[this.props.rowIndex][this.props.columnKey]
it works.
How may I re-build the Cell, so the State gets the new value trough the constructor?
Upvotes: 2
Views: 1755
Reputation: 3866
The problem you are facing is due the component is mounted the state is changed, but then the state never changes again. Adding componentWillReceiveProps
to update the state when new props are passed will solve your problem.
Here the fiddle
var Table = FixedDataTable.Table;
var Column = FixedDataTable.Column;
var Cell = FixedDataTable.Cell;
//Custom header cell
var MyHeaderCell = React.createClass({
mixins: [React.addons.PureRenderMixin],
render: function() {
return <Cell {...this.props}>Column: {this.props.columnKey}</Cell>;
}
})
//Custom cell
var MyCell = React.createClass({
mixins: [React.addons.PureRenderMixin],
getInitialState: function() {
return {
value: this.props.data[this.props.rowIndex][this.props.columnKey]
};
},
componentWillReceiveProps(nextProps){
this.setState({ value: nextProps.data[nextProps.rowIndex][nextProps.columnKey]});
},
render: function() {
return <Cell {...this.props}>Cell: {this.state.value}</Cell>;
}
})
var MyTable = React.createClass({
mixins: [React.addons.PureRenderMixin],
render: function() {
return (
<Table
rowHeight={50}
rowsCount={this.props.data.length}
width={this.props.width}
height={this.props.height}
headerHeight={50}
>
{this.createColumns()}
</Table>
);
},
createColumns: function() {
var columns = [];
for (let i = 0; i < this.props.data[0].length; i++) {
columns.push(
<Column
key={i}
columnKey={i}
rowIndex={this.props.data[0]}
header={<MyHeaderCell />}
cell={<MyCell data={this.props.data} />}
width={this.props.width / this.props.data[0].length}
/>
)
}
return columns;
}
})
var Container = React.createClass({
getInitialState: function() {
return {
iR: [
['a1', 'b1', 'c1'],
['a2', 'b2', 'c2'],
['a3', 'b3', 'c3'],
]
};
},
changeData: function() {
var newiR = [
['x1', 'k1', 'w1'],
['x2', 'k2', 'w2'],
['x3', 'k3', 'w3'],
];
this.setState({ iR: newiR });
},
render: function() {
return (
<div>
<button onClick={this.changeData}>Change Data</button>
<MyTable height={this.props.height} width={this.props.width} data={this.state.iR} />
</div>
);
}
})
var container = document.getElementById('container');
// Render your table
function render() {
var height = container.offsetHeight;
var width = container.offsetWidth;
ReactDOM.render(<Container height={height} width={width}/>,
document.getElementById('container'));
}
window.onresize = render;
render();
I've moved some code just to make it consistent with React.
I strongly reccomend you to take a look at React Component Cycle Life
Upvotes: 1