React setState改变了孩子的道具

时间:2017-10-23 20:31:29

标签: javascript reactjs

所以我的目标是让一个反应组件,如果按一个按钮,基本上可以让你拥有一些子组件。我想管理顶级组件中的状态,当你点击提交时,我希望这个组件的状态基本上是一个对象数组,列表中每个组件的一个元素。我对解决方案的想法是渲染一些子组件并向它们传递索引。然后,我给他们上层onChange函数,让他们用索引调用。这个问题是它在我在上层this.setState函数中调用onChange之前一直有效。出于某种原因,调用this.setState会导致我的index参数始终是子元素列表中的最高数字索引。

这是AddressesDataForm.js:

export default class AddressesDataForm extends React.Component {

constructor(props) {
    super(props);
    if (this.props.onChange) {
        functions.onChange = this.onChange;
    }
    if(this.props.onSubmit) {
        functions.onSubmit = this.props.onSubmit;
    }
    this.state = {
        'tableName': 'Addresses',
        states: [
            'Gotta',
            'Hook',
            'Into',
            'State',
            'Api',
            'Still'
        ],
        county_disabled: true,
        counties: {
            'Gotta': ['a', 'b', 'c'],
            'Hook': ['d', 'e', 'f'],
            'Into': ['e', 't', 'c'],
            'State': ['e', 't', 'c'],
            'Api': ['e', 't', 'c'],
            'Still': ['e', 't', 'c']
        },
        use_counties: [],
        countries: [
            'United States of America',
            'Elsewhere'
        ],
        index: this.props.index
    }
    console.log(this.props.index);
}

onChange = (name, value) => {
    if (name == 'state') {
        if (value.length > 0) {
            this.setState({
                county_disabled: false,
                use_counties: this.state.counties[value]
            });
        } else {
            this.setState({
                county_disabled: true
            });
        }
    }
    console.log(this.props.index); //notice this.props.index, tried this.state as well and it didn't work either
    this.props.onChange(name, value, this.props.index);
}

render() {
    return (
        <DataForm tableName={this.state.tableName} onSubmit={functions.onSubmit.bind(this)} {...this.props}>
            <SelectField
                menuItems={['Home', 'Work', 'Other']}
                defaultValue="Home"
                className='md-cell md-cell--2 md-cell--middle'
                onChange={functions.onChange.bind(this, "address_type_select")}
            />
            <TextField
                label="Street Address Line 1"
                maxLength={128}
                className='md-cell md-cell--10'
                onChange={functions.onChange.bind(this, "address_line_1")}
            />
            <TextField
                label="Street Address Line 2"
                maxLength={128}
                className='md-cell md-cell--2-desktop-offset md-cell--10'
                onChange={functions.onChange.bind(this, "address_line_2")}
            />
            <TextField
                label="City"
                maxLength={64}
                className='md-cell md-cell--2-desktop-offset md-cell--5'
                onChange={functions.onChange.bind(this, "city")}
            />
            <SelectField
                label="State"
                maxLength={64}
                className='md-cell md-cell--2'
                menuItems={this.state.states}
                onChange={this.onChange.bind(this, "state")}
            />
            <TextField
                label="ZIP code"
                className='md-cell md-cell--3'
                onChange={functions.onChange.bind(this, "zip_code")}
                required
            />
            <SelectField
                label="Country"
                className='md-cell md-cell--2-desktop-offset md-cell--10'
                menuItems={this.state.countries}
                defaultValue={this.state.countries[0]}
                onChange={functions.onChange.bind(this, "country")}
            />
            <h6 className="md-cell md-cell--2-desktop-offset md-cell--10">Location Information</h6>
            <SelectField
                label="County"
                className='md-cell md-cell--2-desktop-offset md-cell--10'
                menuItems={this.state.use_counties}
                onChange={this.onChange.bind(this, "county")}
                helpText={this.state.county_disabled ? 'Select a state' : ''}
                disabled={this.state.county_disabled}
            />
            <SelectionControl
                id={"switch-primary-address" + this.props.index}
                className='md-cell md-cell--12 md-cell--2-desktop-offset'
                type="switch"
                label="Primary address"
                onChange={functions.onChange.bind(this, "primary_address")}
                checked={this.props.isPrimary}
            />
            {this.props.noAddButton ?
                null :
                <div className="md-cell">
                    <Button
                        style={{ display: "inline-block" }}
                        floating mini secondary
                        onClick={this.props.onAddClicked}>
                        add circle
                    </Button>
                    <p style={{ display: "inline-block", margin: "10px" }}>Add address</p>
                </div>}
            {this.props.noButton ? null : <h6 className="md-cell md-cell--12">* Required Fields</h6>}
            <p>{this.props.index}</p>
        </DataForm>
    );
}

}

和AddressesDeck.js

export default class AddressesDeck extends React.Component {

constructor(props) {
    super(props);
    this.state = {
        addresses: 3,
        primaryAddress: 0,
        data: {}
    };
}

onAddClicked = () => {
    this.setState({
        addresses: this.state.addresses + 1,
        primaryAddress: this.state.addresses
    });
}

onChange = (name, value, index) => {
    console.log(index); //properly logs the index
    // this.setState(prevState => ({ //unless this is un-commented, then it always logs 2
    //     'something unrelated':value
    // }));
    console.log(this.state);
    // if (name == 'primary_address') {
    //     this.setState({
    //         primaryAddress: index
    //     });
    // }
}

render() {
    return (
        // <div>
        //     {[...new Array(this.state.addresses)].map((_, i) => (
        //         <Paper id="main" key={i}>
        //             <AddressesDataForm
        //                 onChange={this.onChange.bind(this, i)}
        //                 onSubmit={functions.onSubmit.bind(this)}
        //                 key={i}
        //                 index={i}
        //                 onAddClicked={this.onAddClicked.bind(this)}
        //                 noButton={i != this.state.addresses - 1}
        //                 noAddButton={i != this.state.addresses - 1 || this.state.addresses == 3}
        //                 noTitle={i != 0}
        //                 isPrimary={this.state.primaryAddress == i} />
        //         </Paper>
        //     ))}
        // </div>
        <div>
            <Paper id="main" key={0}>
                <AddressesDataForm
                    onChange={this.onChange}
                    onSubmit={functions.onSubmit.bind(this)}
                    key={0}
                    index={0}
                    onAddClicked={this.onAddClicked.bind(this)}
                    noButton={0 != this.state.addresses - 1}
                    noAddButton={0 != this.state.addresses - 1 || this.state.addresses == 3}
                    noTitle={0 != 0}
                    isPrimary={this.state.primaryAddress == 0} />
            </Paper>
            <Paper id="main" key={1}>
                <AddressesDataForm
                    onChange={this.onChange}
                    onSubmit={functions.onSubmit.bind(this)}
                    key={1}
                    index={1}
                    onAddClicked={this.onAddClicked.bind(this)}
                    noButton={1 != this.state.addresses - 1}
                    noAddButton={1 != this.state.addresses - 1 || this.state.addresses == 3}
                    noTitle={1 != 0}
                    isPrimary={this.state.primaryAddress == 1} />
            </Paper>
            <Paper id="main" key={2}>
                <AddressesDataForm
                    onChange={this.onChange}
                    onSubmit={functions.onSubmit.bind(this)}
                    key={2}
                    index={2}
                    onAddClicked={this.onAddClicked.bind(this)}
                    noButton={2 != this.state.addresses - 1}
                    noAddButton={2 != this.state.addresses - 1 || this.state.addresses == 3}
                    noTitle={2 != 0}
                    isPrimary={this.state.primaryAddress == 2} />
            </Paper>
        </div>
    );
}

}

1 个答案:

答案 0 :(得分:1)

这可能是因为在构造函数中,您将this.onChange分配给functions对象,该对象在AddressesDataForm组件的所有实例之间共享。第一次渲染每个实例时,刚刚调用了构造函数,functions.onChange将具有正确的值。但是,在设置父级状态并重新渲染每个实例时,不会调用构造函数,并且三个渲染中的每个渲染中的functions.onChange将引用第三个this.onChange(使用索引调用this.props.onChange 2。)

在没有运行代码的情况下有点难以看到,但我想只需使用this.onChange即可解决问题。另外,为防止混淆,您可以将传递给AddressesDataForm的道具重命名为onchange以外的其他内容。