Sync react state with hot internal state

Tags: #<Tag:0x00007f8b2b01df48>

I really struggle to understand how to use react-handsontable. I want handsontable to take care of all mutation in its internal state but also keep this state in sync with react component state. I have followed the examples in the docs but none of them achieve this.

My best attempt so far is something like this:

class Table extends React.Component {
  shouldComponentUpdate() {
    return false; // This prevents an error with infinite loop
  }

  render() {
    const { settings, setTableInstance } = this.props;
    return <HotTable settings={settings} ref={table => setTableInstance(table)} />;
  }
}

class TableContainer extends React.Component {
  constructor() {
    super()
    this.state = { data: [[null, null, null], [null, null, null]] } // Example initial content
    this.setData = this.setData.bind(this)
  }

  setData() {
    if (this.table) {
      this.setState({ data: this.table.getData() })
    }
  }

  render() {
    const { data } = this.state
    const settings = {
      data,
      onAfterChange: this.setData,
 contextMenu: true,
    }
    return (
      <div>
        <Table
          settings={settings}
          setTableInstance={table => this.table = table.hotInstance}
        />
      </div>
    )
  }
}

But then I also need to bind on all other events like afterCreateRow, afterRemoveRow to make sure my data is in sync.

Hey @onoufrios

can you work on a specific scenario? It will be easier to track down the issues.

I have a demo here https://codepen.io/anon/pen/XEBvVe?editors=0010 that we can use for tests.

So in your example if you edit a cell, this.handsontableData doesn’t actually get updated. I would expect that to be updated in order for me to send an api request to update the table in the database.

Or maybe there is a better way to do this?

Just to reiterate what I am expecting, which is what usually happens with other react wrappers:
I expect the data flow to be unidirectional from parent to child. And the source of truth for the current table value to be held by the parent. In an ideal scenario I would expect something like below:

class TableExample extends React.Component {
  constructor() {
     super()
     const data  = [...] // some initial data
     this.state = { data  }
  }

  onChange(newTableContent) {
     this.setState({ data: newTableContent })
  }

  render() {
    <HotTable 
       data={this.state.data}
       onChange={this.onChange} 
       ref={table => this.table = table}
    />
  }
}

Where props do the following
onChange: An event firing every time the table is changed (Edit cell, new row, selection e.t.c.). The internal value of hot doesn’t change until we update this.state.data which will cause the hot to rerender because its props have changed.
ref: Maybe we add this in order to get a reference to the hot table. Anytime we use this to alter the handsontable (e.g. table.alter(‘insert_row’, 2)) the handsontable value doesn’t actually change internally. It just fires another onChange event.

I understand that the above might not be achievable with the current react wrapper. But what would be the alternative to try and get as close as possible to the above?

Hope this helps clarify a bit what I want.

You should be able to update data via loadData method, but I would need to see a working demo to test it.