How to get values ​​from child components in React

So, I'm just starting to use React, and it's hard for me to collect the input values ​​of the input data in a child component. Basically, I create various components for the large form that I create, and then in the enclosing component I want to collect all the input values ​​for the children in the object I call, and then send the collected input to POST AJAX (you can see an example in the last component that I did). I can get the values ​​easily enough when I'm inside the components, but pull them out of the parent component, which I did not understand.

Thanks in advance. Just relieving the pain right now with React, so any advice on how to structure it better, I'm all ears!

Here are my components:

Component 1

var StepOne = React.createClass({ getInitialState: function() { return {title: '', address: '', location: ''}; }, titleChange: function(e) { this.setState({title: e.target.value}); }, addressChange: function(e) { this.setState({address: e.target.value}); }, locationChange: function(e) { this.setState({location: e.target.value}); }, render: function() { return ( <div className="stepOne"> <ul> <li> <label>Title</label> <input type="text" value={this.state.title} onChange={this.titleChange} /> </li> <li> <label>Address</label> <input type="text" value={this.state.address} onChange={this.addressChange} /> </li> <li> <label>Location</label> <input id="location" type="text" value={this.state.location} onChange={this.locationChange} /> </li> </ul> </div> ); }, // render }); // end of component 

Component second

 var StepTwo = React.createClass({ getInitialState: function() { return {name: '', quantity: '', price: ''} }, nameChange: function(e) { this.setState({name: e.target.value}); }, quantityChange: function(e) { this.setState({quantity: e.target.value}); }, priceChange: function(e) { this.setState({price: e.target.value}); }, render: function() { return ( <div> <div className="name-section"> <div className="add"> <ul> <li> <label>Ticket Name</label> <input id="name" type="text" value={this.state.ticket_name} onChange={this.nameChange} /> </li> <li> <label>Quantity Available</label> <input id="quantity" type="number" value={this.state.quantity} onChange={this.quantityChange} /> </li> <li> <label>Price</label> <input id="price" type="number" value={this.state.price} onChange={this.priceChange} /> </li> </ul> </div> </div> </div> ); } }); 

The final component to collect data and send an ajax request

 EventCreation = React.createClass({ getInitialState: function(){ return {} }, submit: function (e){ var self e.preventDefault() self = this var data = { // I want to be able to collect the values into this object then send it in the ajax request. I thought this sort of thing would work below: title: this.state.title, } // Submit form via jQuery/AJAX $.ajax({ type: 'POST', url: '/some/url', data: data }) .done(function(data) { self.clearForm() }) .fail(function(jqXhr) { console.log('failed to register'); }); }, render: function() { return( <form> <StepOne /> <StepTwo /> // submit button here </form> ); } }); 
+5
source share
4 answers

Define methods in child components that return the data you want, and then in the parent component when rendering the children, later define refs, when you want to get the data you need, you can call these methods on children.

 StepOne = React.createClass({ getData: function() { return this.state; } }); StepTwo = React.createClass({ getData: function() { return this.state; } }); EventCreation = React.createClass({ submit: function() { var data = Object.assign( {}, this._stepOne.getData(), this._stepTwo.getData() ); // ... do AJAX }, render: function() { return ( <StepOne ref={(ref) => this._stepOne = ref} /> <StepTwo ref={(ref) => this._stepTwo = ref} /> ); } }); 
+6
source

Generally speaking, you will want to transfer the function from parent to children as a pillar. When the children’s data changes, they will call this function as a callback.

This has the big advantage of allowing your parent component to keep track of the entire state of your application and pass state slices as props for its children, rather than each component tracking its own internal state. ( This is a React approach to data flow .)

Your components might look something like this:

 var StepOne = React.createClass({ handleOnChange: function(e){ this.props.handleChange(e.target.name, e.target.value); }, render: function() { return ( <div className="stepOne"> <ul> <li> <label>Title</label> <input type="text" name="title" value={this.props.title} onChange={this.handleChange} /> </li> ... </ul> </div> ); }, // render }); // end of component EventCreation = React.createClass({ getInitialState: function(){ return {} }, handleChange: function(name, value){ var tmp = {}; tmp[name] = value; this.setState(tmp); }, submit: function (e){ var self e.preventDefault() self = this var data = { // I want to be able to collect the values into this object then send it in the ajax request. I thought this sort of thing would work below: title: this.state.title, } // Submit form via jQuery/AJAX $.ajax({ type: 'POST', url: '/some/url', data: data }) .done(function(data) { self.clearForm() }) .fail(function(jqXhr) { console.log('failed to register'); }); }, render: function() { return( <form> <StepOne handleChange={this.handleChange.bind(this)} title={this.state.title} .../> <StepTwo handleChange={this.handleChange.bind(this)} ... /> // submit button here </form> ); } }); 
+3
source

First you need to set the link. This will allow you to easily get to some DOM elements. Example:

 <input id="name" type="text" value={this.state.ticket_name} onChange={this.nameChange} ref="stepOneName"/> 

Then in your submit method, you can return it like this:

 var data = { name: this.refs.stepOneName.value } 

EDIT 1: You should also add ref to your components:

render: function () {return (// send the button here); } Then access to your element:

 var data = { name: this.refs.steOneRef.refs.stepOneName.value } 

I JSFiddled your ant code it seems to me that this is normal.

+1
source

Here's a slightly more loosely coupled solution. It depends on how you set the id for each element. Basically, what you do is calling the onChange function of the parent components, which will receive and set the data.

 var StepOne = React.createClass({ getInitialState: function() { return {title: '', address: '', location: ''}; }, _onChange(e) { // set your state if needed // call the parent function this.props.onChange( e.target.id, e.target.value ) }, render: function() { return ( <div className="stepOne"> <ul> <li> <label>Title</label> <input id="title" type="text" value={this.state.title} onChange={this._onChange.bind(this)} /> </li> <li> <label>Address</label> <input id="address" type="text" value={this.state.address} onChange={this._onChange.bind(this)} /> </li> <li> <label>Location</label> <input id="location" type="text" value={this.state.location} onChange={this._onChange.bind(this)} /> </li> </ul> </div> ); }, // render }); // end of component var StepTwo = React.createClass({ getInitialState: function() { return {name: '', quantity: '', price: ''} }, _onChange(e) { // set your state if needed // call the parent function this.props.onChange( e.target.id, e.target.value ) }, render: function() { return ( <div> <div className="name-section"> <div className="add"> <ul> <li> <label>Ticket Name</label> <input id="name" type="text" value={this.state.ticket_name} onChange={this._onChange.bind(this)} /> </li> <li> <label>Quantity Available</label> <input id="quantity" type="number" value={this.state.quantity} onChange={this._onChange.bind(this)} /> </li> <li> <label>Price</label> <input id="price" type="number" value={this.state.price} onChange={this._onChange.bind(this)} /> </li> </ul> </div> </div> </div> ); } EventCreation = React.createClass({ getInitialState: function(){ return {} }, _onChange(id, value) { this.formData[id] = value; }, submit: function (e){ var self e.preventDefault() self = this // Submit form via jQuery/AJAX $.ajax({ type: 'POST', url: '/some/url', data: this.formData }) .done(function(data) { self.clearForm() }) .fail(function(jqXhr) { console.log('failed to register'); }); }, render: function() { return( <form> <StepOne onChange={this.onChange.bind(this)}/> <StepTwo onChange={this.onChange.bind(this)}/> // submit button here </form> ); } }); 
0
source

Source: https://habr.com/ru/post/1244443/


All Articles