1

I'm trying to make reusable toggle function.

Component initial state:

constructor(props) {
    super(props);

    this.state = {
        collapseFirst: false,
        collapseSecond: false
    };
}

Toggle function (it should change true/false state based on collapse target clicked):

handleToggle = e => {
    const collapseItem = e.target.getAttribute('data-control');
    this.setState({
        [collapseItem]: !this.state.collapseItem
    });
};

Rendered elements (using Reactstrap Collapse component):

return (
    <div>
        <Button color="primary" onClick={this.props.toggle} data-control="collapseFirst">
            First Collapse
        </Button>
        <Collapse isOpen={this.props.collapseFirst}>
            <p>Some text</p>
        </Collapse>
        <Button color="primary" onClick={this.props.toggle} data-control="collapseSecond">
            Second Collapse
        </Button>
        <Collapse isOpen={this.props.collapseSecond}>
            <p>Some another text</p>
        </Collapse>
    </div>
);

The problem is that for some reason collapseItem returns expected data-control value but this.state.collapseItem is undefined.

What am I doing wrong?

4

1 回答 1

1

You got your variable names and values mixed up. Don't worry, especially with some of these ES6 syntaxes it happens to the best of us.

collapseItem is not a property on this.state. The only properties on the this.state object are collapseFirst and collapseSecond.

In handleToggle(), you create a constant called collapseItem. This statement:

[collapseItem]: !this.state.collapseItem

uses the ES6 computed property syntax. This takes the string value of collapseItem and creates a property on the object with that value as the key.

Since the value of collapseItem should be either 'collapseFirst' or 'collapseSecond' this means we'll create a property on the object named either collapseFirst or collapseSecond, NOT collapseItem.

The statement

!this.state.collapseItem

will always return true because, as I said, this.state.collapseItem does not exist and will thus return undefined. !undefined is true.

I believe you meant to do:

[collapseItem]: !this.state[collapseItem]

This will grab the value of the appropriate property from the existing state.

Also, just a side note, when the new state is dependent on the previous state, you should typically use the following setState() overload:

this.setState(state => ({
    [collapseItem]: !state[collapseItem]
})

Read up on that here

于 2018-01-01T16:29:57.607 回答