4

I am using react-table with mbox and have run into a issue where my state is not updating.

I have a table like this

<ReactTable
  data={data}
  columns={columns}
  showPageSizeOptions={false}
  resizable={false}
  className="-striped -highlight"
  defaultPageSize={12}
  filterable={true}
/>

A column that has

{
  Header: "",
  accessor: "checkbox",
  filterable: false,
  width: 35,
  Cell: ({ original }) => {
    return (
      <input
        type="checkbox"
        className="checkbox"
        checked={employeeUiStore.selectedEmployees.indexOf(original.id) >= 0 }
        onChange={() => employeeUiStore.toggleCheckbox(original.id)}
      />
    );
  }
},

and a store like this

class EmployeeUiStore {
  @observable addMode = false;
  @observable selectedEmployees = []
  constructor(){}
  @action
  toggleCheckbox(employeeId) {
    const index = this.selectedEmployees.indexOf(employeeId);
    if(index === -1){
      this.selectedEmployees = [...this.selectedEmployees, employeeId];
    }else {
      const newSelectedEmployees = [...this.selectedEmployees];
      newSelectedEmployees.splice(index, 1);
      this.selectedEmployees = newSelectedEmployees;
    }
  }  
  @action
  toggleAddEmployee(){
      this.addMode = !this.addMode;
  }
}
export default EmployeeUiStore;

The weird thing is if I add something like this to my code

console.log(employeeUiStore.selectedEmployees.indexOf(0) >= 0)

Then states will update properly but when I remove this line then nothing is updated.

I see that my toggleCheckbox is being triggered and the state is being updated.

I also do have @observer on this component.

Tholle
  • 108,070
  • 19
  • 198
  • 189
chobo2
  • 83,322
  • 195
  • 530
  • 832

1 Answers1

3

You are not dereferencing anything when you pass the data array to the ReactTable component.

You can resolve this by either using slice or peek on the array before you pass it to external libraries:

<ReactTable
  data={data.slice()}
  columns={columns}
  showPageSizeOptions={false}
  resizable={false}
  className="-striped -highlight"
  defaultPageSize={12}
  filterable={true}
/>

There is also no need for immutability in MobX. You can alter the array straight away:

class EmployeeUiStore {
  @observable addMode = false;
  @observable selectedEmployees = [];

  @action
  toggleCheckbox(employeeId) {
    const index = this.selectedEmployees.indexOf(employeeId);
    if (index === -1) {
      this.selectedEmployees.push(employeeId);
    } else {
      this.selectedEmployees.splice(index, 1);
    }
  }

  @action
  toggleAddEmployee(){
    this.addMode = !this.addMode;
  }
}

export default EmployeeUiStore;
Tholle
  • 108,070
  • 19
  • 198
  • 189
  • Is peek a built in? I am getting undefined. I tried using slice like columns.slice().sort() but still not 100% working. the actually checkbox does not actually check. – chobo2 Jul 10 '18 at 20:45
  • @chobo2 My bad, I used `peek` on the wrong array. You should use it on the observable `data`. Yes, it's a MobX built in. – Tholle Jul 10 '18 at 20:49
  • do I need to import something, I get "peek is not a function" – chobo2 Jul 10 '18 at 21:52
  • @chobo2 That's frustrating. `slice` works just as well. I updated the answer to that. You can also mutate your data straight away, no need for immutable techniques. I updated `toggleCheckbox` in the answer. – Tholle Jul 10 '18 at 22:00
  • yea, that was left over code from when I was just using reactjs state. It works better but still not 100%. I have 3 rows in the table, it starts off ok, once I start click a few times it seems like it loses the state. Could it be because the data is actually an array made from Mobx State Tree? – chobo2 Jul 10 '18 at 22:18
  • @chobo2 If it stops working after the 1 click it is most likely because of the immutable React-like code. If you overwrite the observable array (`this.selectedEmployees = [ ... ]`) with a regular array, it will stop being observable. – Tholle Jul 10 '18 at 22:21
  • @ Tholle - I changed my code to what you have. It still loses state after a few clicks. – chobo2 Jul 10 '18 at 22:55