palantir / blueprint

A React-based UI toolkit for the web
https://blueprintjs.com/
Apache License 2.0
20.71k stars 2.17k forks source link

[Table] wrapped table with onSelection listener doesn't allow select-all #1233

Open seansfkelley opened 7 years ago

seansfkelley commented 7 years ago

Bug report

Steps to reproduce

Using this table-containing component:

interface State {
    selection: IRegion[];
}

export class BuggyTable extends React.PureComponent<{}, State> {
    public state: State = {
        selection: [],
    };

    public render() {
        return (
            <Table
                numRows={1}
                selectionModes={SelectionModes.ALL}
                onSelection={this.updateSelection}
            >
                <Column
                    name="foo"
                    renderCell={(rowIndex) => <Cell>bar</Cell>}
                />
            </Table>
        );
    }

    private updateSelection = (selection: IRegion[]) => {
        this.setState({ selection });
    };
}
  1. Click on the top-left-most header cell (the "select all" cell).

Actual behavior

  1. Selection does not change from it's current state.

Expected behavior

  1. Selection is set to "all cells".

Commenting out the this.setState line causes selection to behave as expected again. Wrapping this.setState in a zero-duration setTimeout also causes selection to behave as expected. Looks like some kind of synchronicity/deferral issue?

Confusingly, all other types of selection work (entire-row, entire-column, single-cell, multiple-cell).

cmslewis commented 7 years ago

Oh this sounds interesting. Will dig in this week. 👍

cmslewis commented 7 years ago

Man, I'm just not seeing what's going on with this one. For some reason, when selectAll() invokes Table.handleSelection (a private helper), the state is not updated before componentWillReceiveProps is invoked.

Fortunately, passing the selectedRegions back into Table in a controlled fashion fixes the issue.