admin管理员组

文章数量:1220959

I have 3 components in React, one acts as a container which passes down my child components to be rendered in a form. When the form is submitted I want to get each of the child components in my parent component, loop through each one, create an object my server expects then send the list of objects back to the server. I am struggling to access the child components in my onSubmit function in my parent component.

Here is my parent component

ParentFixturesComponent.js

class ParentFixturesComponent extends Component {

    constructor() {
        super();
        this.state = {
            numChildren: 0,
        };
    }

    onAddMatch() {
        this.setState({
            numChildren: this.state.numChildren + 1
        });
    }

    onSubmit(e) {
        e.preventDefault();
        // loop through the child components
        // create a match object with them
        // var match = {
        //     id: uuid(),
        //     title: uuid(),
        //     start: e.something,
        //     end: e.something,
        // };
        console.log("submit works");
    }

    render() {
        const children = [];
        for (let i = 0; i < this.state.numChildren; i += 1) {
            children.push(<SingleMatchForm key={uuid()}/>)
        }

        return (
            <Fixtures addMatch={this.onAddMatch.bind(this)} save={this.onSubmit.bind(this)} >
                {children}
            </Fixtures>
        );
    }

}

export default ParentFixturesComponent;

Component which holds my form where my parent renders all my children components

ChildFixturesContainer.js

class Fixtures extends Component {


    constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(name) {
        this.console.log(this.props);
    }

    render() {
        return (
            <div className="tray tray-center">
                <div className="row">
                    <div className="col-md-8">
                        <div className="panel mb25 mt5">
                            <div className="panel-heading">
                                <span className="panel-title">Fixtures</span>
                            </div>
                            <div className="panel-body p20 pb10">
                                <div id="fixture-parent" onChange={this.handleChange.bind(this)}>
                                    {this.props.children}
                                </div>
                            </div>
                            <div className="section-divider mb40" id="spy1"> </div>
                            <button className="btn btn-primary tm-tag" onClick={this.props.addMatch}>Add Match</button>
                            <button className="btn btn-alert tm-tag" onClick={this.props.save}>Save</button>
                        </div>
                    </div>
                </div>
            </div>
        );
    }

}

export default Fixtures;

And finally my child individual form component.

SingleMatchComponent.js

class SingleMatchForm extends Component {

    constructor() {
        super();
        this.state = {
            startDate: moment()
        };
    }

    handleChange(date) {
        this.setState({
            startDate: date
        });
    }

    render() {
        return (
            <div className="row">
                <div key={this.props.id} className="form-group">
                    <label className="control-label col-md-2">New Match</label>
                    <div className="col-md-6">
                        <DatePicker
                            selected={this.state.startDate}
                            onChange={this.handleChange.bind(this)}/>
                        <div className="section-divider mb40" id="spy1"> </div>
                    </div>
                </div>
            </div>
        );
    }

}

export default SingleMatchForm;

I have 3 components in React, one acts as a container which passes down my child components to be rendered in a form. When the form is submitted I want to get each of the child components in my parent component, loop through each one, create an object my server expects then send the list of objects back to the server. I am struggling to access the child components in my onSubmit function in my parent component.

Here is my parent component

ParentFixturesComponent.js

class ParentFixturesComponent extends Component {

    constructor() {
        super();
        this.state = {
            numChildren: 0,
        };
    }

    onAddMatch() {
        this.setState({
            numChildren: this.state.numChildren + 1
        });
    }

    onSubmit(e) {
        e.preventDefault();
        // loop through the child components
        // create a match object with them
        // var match = {
        //     id: uuid(),
        //     title: uuid(),
        //     start: e.something,
        //     end: e.something,
        // };
        console.log("submit works");
    }

    render() {
        const children = [];
        for (let i = 0; i < this.state.numChildren; i += 1) {
            children.push(<SingleMatchForm key={uuid()}/>)
        }

        return (
            <Fixtures addMatch={this.onAddMatch.bind(this)} save={this.onSubmit.bind(this)} >
                {children}
            </Fixtures>
        );
    }

}

export default ParentFixturesComponent;

Component which holds my form where my parent renders all my children components

ChildFixturesContainer.js

class Fixtures extends Component {


    constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(name) {
        this.console.log(this.props);
    }

    render() {
        return (
            <div className="tray tray-center">
                <div className="row">
                    <div className="col-md-8">
                        <div className="panel mb25 mt5">
                            <div className="panel-heading">
                                <span className="panel-title">Fixtures</span>
                            </div>
                            <div className="panel-body p20 pb10">
                                <div id="fixture-parent" onChange={this.handleChange.bind(this)}>
                                    {this.props.children}
                                </div>
                            </div>
                            <div className="section-divider mb40" id="spy1"> </div>
                            <button className="btn btn-primary tm-tag" onClick={this.props.addMatch}>Add Match</button>
                            <button className="btn btn-alert tm-tag" onClick={this.props.save}>Save</button>
                        </div>
                    </div>
                </div>
            </div>
        );
    }

}

export default Fixtures;

And finally my child individual form component.

SingleMatchComponent.js

class SingleMatchForm extends Component {

    constructor() {
        super();
        this.state = {
            startDate: moment()
        };
    }

    handleChange(date) {
        this.setState({
            startDate: date
        });
    }

    render() {
        return (
            <div className="row">
                <div key={this.props.id} className="form-group">
                    <label className="control-label col-md-2">New Match</label>
                    <div className="col-md-6">
                        <DatePicker
                            selected={this.state.startDate}
                            onChange={this.handleChange.bind(this)}/>
                        <div className="section-divider mb40" id="spy1"> </div>
                    </div>
                </div>
            </div>
        );
    }

}

export default SingleMatchForm;
Share Improve this question asked May 13, 2017 at 13:19 N PN P 2,6197 gold badges37 silver badges57 bronze badges 1
  • Hi Nick, you should pass functions as props from parent to child, which act as callbacks. So when onSubmit() function is called you will have all data in your parent components state. For sample code refer to this thread stackoverflow.com/questions/38394015/… – Rishabh Bhatia Commented May 13, 2017 at 13:39
Add a comment  | 

2 Answers 2

Reset to default 13

Define a function in your parent and send it to the child, call the parent function in child component using props. Something like:

Parent

class ParentFixturesComponent extends Component {

    // don't forget to bind the function in parent
    constructor() {
        super();
        this.state = {
            numChildren: 0,
        };
        this.someFunctionHere = this.someFunctionHere.bind(this);
    }

    someFunctionHere(param) {
        // do whatever you need
    }

    render() {
        const children = [];
        for (let i = 0; i < this.state.numChildren; i += 1) {
            children.push(<SingleMatchForm key={uuid()}/>)
        }

        return (
            <Fixtures
                addMatch={this.onAddMatch.bind(this)}
                save={this.onSubmit.bind(this)}
                someFunctionHere={this.someFunctionHere}
            >
                {children}
            </Fixtures>
        );
    }
}

export default ParentFixturesComponent;

Child

class Fixtures extends Component {

    // constructor and other stuff...

    childFunctionHere() {
        this.props.someFunctionHere(params);            
    }

    render() {
        return (
            <div id="fixture-parent" onChange={this.childFunctionHere}>
        );
    }
}

export default Fixtures;

Essentially, you're asking about the difference between props and state.

There are two types of data that control a component: props and state. props are set by the parent and they are fixed throughout the lifetime of a component. For data that is going to change, we have to use state. Docs

This also addresses smart/dumb (or logic/display or container/presenter) components.

Your parent component should hold all of the state and the logic for changing it, then pass everything down to the other components as props. Your child components shouldn't really even have a state they just handle displaying it and, when something happens, they just send that call back up to the parent component to do whatever needs to be done.

When the child components call those handlers via props, they'll execute in the parent, updating the state there. Then you can just collect the state in the parent and submit it.

class TheParent extends component {

  constructor() {
    super();
    this.state = {
      someState: 0,
      someMoreState: 1,
      evenMoreState: 2
    };
    autoBind(this) // <- use autobind so you don't have to list them all out
  }

  updateSomeState() {
        // do something
  }

  updateSomeMoreState() {
        // do something
  }

  updateEvenMoreState() {
        // do something
  }

  onSubmit() {
    // get state and submit
  }

  render () {
    return (
      <Component1 
        someProp={this.state.someState} 
        handler={this.updateSomeState} 
      />
      <Component2 
        someProp={this.state.someMoreState} 
        handler={this.updateSomeMoreState} 
      />          
      <Component2 
        someProp={this.state.evenMoreState} 
        handler={this.updateEvenMoreState} 
      />
    )
  }

}

本文标签: javascriptPass data from child to parent in ReactStack Overflow