Leandro Soares
Leandro Soares

Reputation: 2972

Fixed-data-table-2 - React not updating table Cells

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();

JSFiddle

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

Answers (1)

Facundo La Rocca
Facundo La Rocca

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

Related Questions