title: Editable DataTables table in ReactJS
body: <p>I have a basic ReactJS+Flux application where is a table (jQuery DataTables plugin) as a main component. When I click on cell 'Delete row' in first column, data of row are deleted and application sets new state with new data, but table isn't rendered with new data. </p>
  
  <p>In <a href="https://jsfiddle.net/69z2wepo/14715/" rel="nofollow">this</a> example, I don't use jQuery DataTables plugin and table is rendered with new data.</p>
  
  <p>I found <a href="https://discuss.reactjs.org/t/react-js-crud-using-datatables/110" rel="nofollow">this</a> discussion and it seems like in the end it is not possible to create editable DataTables table in ReactJS?</p>
  
  <p><a href="https://jsfiddle.net/69z2wepo/14712/" rel="nofollow">jsfiddle</a> </p>
  
  <pre><code>var dataOr = [{id:1, fstname: "John", sndname: "smith"},
                  {id:2, fstname: "Mathew", sndname: "Lodd"},
                  {id:3, fstname: "Lenny", sndname: "Alva"},
                  {id:4, fstname: "Emery", sndname: "Limford"}];
  
  var fluxObj = Flux.Dispatcher;
  var AppDispatcher = new fluxObj();
  
  function Actions(){
  
      this.deleteItem = function(locationId){
          AppDispatcher.dispatch({
              actionType: 'ITEM_DELETE',
              id: locationId
          });
      }
  
      this.getAllData = function(){
          AppDispatcher.dispatch({
              actionType: 'GET_ALL_DATA'
          });
      }
  
  }
  
  var Actions = new Actions();
  
  function deleteItem(id) {
  
      console.log('going to destory item with id' + id);
      dataOr = _.remove(dataOr, function(n) {
                return n['id'] != id;
      });
  
      console.log('dataOr');
      console.log(dataOr);
  }
  
  var CHANGE_EVENT = 'change';
  var Store = new EventEmitter();
  
  Store.prototype = {
  
    /**
     * Get the entire collection of TODOs.
     * @return {object}
     */
    getAll: function() {
      return dataOr;
    },
  
    emitChange: function() {
      Store.emit(CHANGE_EVENT);
    },
  
    /**
     * @param {function} callback
     */
    addChangeListener: function(callback) {
      Store.on(CHANGE_EVENT, callback);
    },
  
    /**
     * @param {function} callback
     */
    removeChangeListener: function(callback) {
      Store.removeListener(CHANGE_EVENT, callback);
    }
  
  }
  
  AppDispatcher.register(function(action) {
  
    switch(action.actionType) {
  
      case 'ITEM_DELETE':
        deleteItem(action.id);
        console.log('emit delete');
        Store.prototype.emitChange();
        console.log(dataOr);
        break;
  
      default:
        // no op
    }
  });
  
  var Content = React.createClass({
        getInitialState: function() {
          return {data: Store.prototype.getAll()};
        },
        componentDidMount: function() {
          Store.prototype.addChangeListener(this._onChange);
        },
        componentWillUnmount: function(){
          Store.prototype.removeChangeListener(this._onChange);
        },
        render: function() {
  
          return (
            &lt;div&gt;
              &lt;MainTable ref="mainTable" allData={this.state.data} ItemIdProp={'id'} /&gt;
            &lt;/div&gt;
          );
        },
        _onChange: function() {
          this.setState({data: Store.prototype.getAll()});
        }
      });
  
  var MainTable = React.createClass({
          tableAsJqeryElement: {},
          getInitialState: function(){
              return {
                selectedRow: 0
              }
          },
          componentDidMount: function(){
              var self = this;
  
              // initialize table
              this.tableAsJqeryElement = $('#mytable').DataTable({
                  "bDestroy": true,
                  "bAutoWidth": false,
                "fnDrawCallback": function() {
                      self.forceUpdate();         
                } 
              });
  
          },
          componentDidUpdate: function(){
  
              // make column with checkboxes sortable
              $('#mytable').DataTable({
                  "bDestroy": true
              });
  
          },
          render: function(){
  
              var that = this;
  
              var allKeys = [];
              console.log(this.props.allData);
              this.props.allData.forEach(function(element) {
                  Object.keys(element).forEach(function(key) {
                      if (!(allKeys.indexOf(key) &gt; -1)){
                          allKeys.push(key);
                      }
                  });
              });
  
              var columnNames = _.without(allKeys, this.props.ItemIdProp);
  
              return (
                  &lt;div className="table-responsive"&gt;
                    &lt;div className="toggle_column_wrapper"&gt;
                    &lt;/div&gt;
                      &lt;table className="table table-striped table-bordered table-hover" cellSpacing="0" id="mytable" data-click-to-select="true"&gt;
                          &lt;TableHeader ref="tableHeader" columns={columnNames}/&gt;
                          &lt;TableBody ref={this.props.allData} columns={columnNames} tableData={this.props}/&gt;
                      &lt;/table&gt;
                  &lt;/div&gt;
              );     
          },
          componentWillUnmount: function(){
              this.tableAsJqeryElement.destroy();
          }
       });
  
  var TableHeader = React.createClass({
        render: function() {
  
        console.log('this.props.columns');
              console.log(this.props.columns);
  
          var tableHeaders = this.props.columns.map(function (headerData, i) {
            return (
                  &lt;th key={i}&gt;{headerData}&lt;/th&gt;
            );
          });
  
          return (
              &lt;thead&gt;
                &lt;tr&gt;
                    &lt;th className="icon"&gt;&lt;/th&gt;
                    {tableHeaders}
                &lt;/tr&gt;   
            &lt;/thead&gt;
          );
        }
      });
  
      var TableBody = React.createClass({
        getInitialState: function(){
            return {
                selectedRow: -1
            };
        },
        render: function() {
          var that = this;
          counter = -1;
  
          console.log('this.props.tableData.allData');
          console.log(this.props.tableData.allData);
  
          var tableRows = this.props.tableData.allData.map(function(rowData, j) {
            counter++;
            var itemId = that.props.tableData.allData[counter]['id'];
  
            return (
              &lt;tr key={rowData['id']}&gt;
                  &lt;td&gt;
                      &lt;MinusIcon minusClick={that.handleMinusClick.bind(null, j, itemId)}/&gt;
                  &lt;/td&gt;
                  {
                    that.props.columns.map(function (column, i) {
                          if (column in rowData){
                              return &lt;td key={i}&gt;{rowData[column]}&lt;/td&gt;;
                          } else {
                              return &lt;td key={i}&gt;&lt;/td&gt;;
                          }
                      })
                  }
              &lt;/tr&gt; 
              );
          });
  
          return (
              &lt;tbody&gt;
                  {tableRows}
              &lt;/tbody&gt;
          );
        },
        handleMinusClick: function(rowKey, id) {
            Actions.deleteItem(id);
        }
      });
  
  var MinusIcon = React.createClass({
        render: function() {
          return &lt;div onClick={this.props.minusClick}&gt;Delete row&lt;/div&gt;
        }
      });
  
  React.render(&lt;Content /&gt;, document.getElementById('container'));
  </code></pre>