Maintaining the selected row in a Material-UI table


I had some trouble with this one. The Material-UI table component has a property that allows you specify a callback when selected rows change. It looks like this.
<Table  onRowSelection={this.props.onRowSelection} >

I've defined what to do when the selected row changes in a higher order component as follows.
  selectAccount(rowSelection) {
    this.props.dispatch(acSelectRowAccount(rowSelection));
  }

Actions

As usual, I try to make my components stateless, and instead manage all state data within the redux store. This means that onRowSelection dispatches an action to reigister the selected row. Here's the action.
export function acSelectRowAccount(rowSelection) {
  return {
    type: cs.actions.SELECT_ROW_ACCOUNT,
    payload:rowSelection
  };
}

Reducers

The reducer simply needs to move this selected row value into the store. It comes back from the table handler as an array, but in this particular table I'm not allowing multi selection so I'll just move it to a regular row number.
case cs.actions.SELECT_ROW_ACCOUNT: {
    state = {...state};
    state.view.selectedRow = action.payload[0];
   }
}

Component

When rendering the table, I need to respect the selected row. This is a dumb component with the store data arriving as props, so I render these as table rows, setting the selected property where the row index matches the selected row.
    const accounts = this.props.accounts.fetch.data;
    const selectedRow = this.props.accounts.view.selectedRow;

    const accountList = Object.keys(accounts||{})
    .map ((d,i) => {
      return (
        <TableRow key={i} selected={i===selectedRow}>
          <TableRowColumn>{d}</TableRowColumn>
          <TableRowColumn>{accounts[d].expires.toString()}</TableRowColumn>
          <TableRowColumn>{accounts[d].created.toString()}</TableRowColumn>
          <TableRowColumn>{accounts[d].planId}</TableRowColumn>
        </TableRow>
      );  
    });

So where's the problem?

All these are just simple patterns, and should just work. However I was finding that when the table re-rendered, for example if new items were added, the selected attribute was being reset to undefined, which would then cause an action to reset the value in the store. I read lots of reports of the same issue on github issues and stackoverflow, but could not find a solution, till I stumbled across this property, which is specified on the TableBody component.
         <TableBody deselectOnClickaway={false}>
             {accountList}
         </TableBody>

and now it all works just fine. 





For more like this, see React, redux, redis, material-UI and firebase. Why not join our forum, follow the blog or follow me on twitter to ensure you get updates when they are available.
Comments