简体   繁体   English

反应setState改变孩子的道具

[英]React setState changes child's props

So my goal is to have one react component that essentially lets you have a few of a child component if you press a button. 因此,我的目标是拥有一个React组件,从本质上讲,如果您按下按钮,则可以让您拥有几个子组件。 I want to manage the state in the top-level component, and when you hit submit, I want the state of this component to essentially be an array of objects, one element for each component in the list. 我要管理顶级组件中的状态,当您单击提交时,我希望该组件的状态本质上是一个对象数组,列表中每个组件一个元素。 My idea for a solution was to render a couple of the child components and pass them an index. 我的解决方案想法是呈现几个子组件并将其传递给索引。 Then, I give them the upper-level onChange function for them to call with the index. 然后,我给他们上层onChange函数,让他们使用索引进行调用。 The problem with this is that it works until I call this.setState in the upper-level onChange function. 这个问题是,直到我在上层onChange函数中调用this.setState之前,它都可以工作。 For some reason, calling this.setState causes my index parameter to always be the highest number index in the list of child elements. 由于某种原因,调用this.setState会使我的index参数始终是子元素列表中编号最高的索引。

Here is AddressesDataForm.js: 这是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>
    );
}

} }

and AddressesDeck.js 和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>
    );
}

} }

This probably happens because in the constructor, you assign this.onChange to a functions object, which is shared between all instances of your AddressesDataForm component. 这可能是因为在构造函数中,您this.onChange分配给一个functions对象,该对象在AddressesDataForm组件的所有实例之间共享。 When rendering each instance the first time, the constructor was just called, and functions.onChange will have the correct value. 第一次渲染每个实例时,仅调用了构造functions.onChange ,而functions.onChange将具有正确的值。 However, when setting the parent's state and rerendering each instance, no constructor is called, and functions.onChange in each of the three renderings will refer to the third this.onChange (which calls this.props.onChange with an index of 2.) 但是,在设置父级的状态并重新渲染每个实例时,不会调用任何构造functions.onChange ,并且在三个渲染中的每个functions.onChange中的functions.onChange都将引用第三个this.onChange (它使用索引2调用this.props.onChange )。

It's a little hard to see without running the code, but I would guess that simply using this.onChange would fix the problem. 如果不运行代码,很难看到它,但是我想仅仅使用this.onChange就可以解决问题。 Also, to prevent confusion, you could rename the prop passed down to AddressesDataForm to something other than onchange . 另外,为避免混淆,您可以将传递给AddressesDataForm的prop重命名为onchange以外的其他名称。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM