Eugene Podoliako Eugene Podoliako - 2 months ago 12
React JSX Question

React: how to set default value in component from Ajax

I try to create form for editing existing value. The problem is the initial data which comes from ajax request and as result my component is rendred twice: first with empty values and second when the data comes.
Currenly my code doesn't put received data in form. How can I set obtained data from ajax request in form as init data with posibily edit in futher in this form ?

My component that is responsible for input in form:

export default class FormInputField extends React.Component{

constructor(props) {
super(props);
this.state = {
value : constants.EMPTY_FIELD,
errorDisplay : constants.DISPLAY_NONE,
errorMessage : constants.MESSAGE_DEFAULT_ERROR,
}
this.validation = this.validation.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleBlur = this.handleBlur.bind(this);
}

handleChange(e){
let valid = this.validation(e.target.value);
if (this.props.onChange){
this.props.onChange(e, valid)
}
}

validation(value){
//some validation
this.setState({
value : value,
errorDisplay : errorDisplay,
errorMessage : errorMessage
})
return valid;
}

handleBlur(e) {
this.validation(e.target.value.trim());
}

render(){
return(
<div className="form-group">
<label htmlFor = {this.props.name}>{this.props.title}</label>
<div className="col-sm-10">

<input name={this.props.name}
type="text" className="form-control"
id={this.props.name}
placeholder={this.props.placeholder}
value={this.state.value}
onChange={this.handleChange}
onBlur={this.handleBlur}
/>
</div>
</div>
)
}
}


This component is call form
Parent
component by following way:

return(
<div style={mainFormStyle}>
<form onSubmit={this.handleSubmit} id="addCarWashForm">

<FormInputField
title = "Name*:"
placeholder = "Name"
name = "name"
onChange = {this.handleNameChange}
required = {true}
maxLength = {50}
validation = {this.validationName}
errorMessage = "Error"
defaultValue = {this.state.name.value}
/>


and default value comes from the same
Parant
state which is set by this way:

constructor(props) {
super(props);
this.state = {
name : {value : constants.EMPTY_FIELD, isValid : false}
isCarWashDownload : false
};
this.setCarWashInForm = this.setCarWashInForm.bind(this);
}

componentDidMount(){
if (!this.state.isCarWashDownload){
let link = "/carwash/"+this.props.carWashId;
this.serverRequest = $.get(link, function (result) {
this.setCarWashInForm(result);
}.bind(this));
}

};

setCarWashInForm(carWash){
this.setState({
name : {value : carWash.name, isValid:true},
isCarWashDownload : true
})

}

Answer

Children component is rerendering when its props are change by Parent component, so render in Children and Parent run twice, on initial data, and after setState in ajax call response callback ( because state properties in Parent are set as props of Children ). You can avoid rendering Children component by doing simple if in render method of Parent class.

render(){

    let input=null; //or some loading component to show that something is going on

    if (this.ajaxEnded) //example variable which should be changed on true when data is loaded from ajax call
    input=<FormInputField
                title = "Name*:"
                placeholder = "Name"
                name = "name"
                onChange = {this.handleNameChange}
                required = {true}
                maxLength = {50}
                validation = {this.validationName}
                errorMessage = "Error"
                defaultValue = {this.state.name.value}
            />      

   return(

     <div style={mainFormStyle}>
        <form onSubmit={this.handleSubmit} id="addCarWashForm">
        {input}
        </form>
     </div>

  );

 }

So we show nothing or loading in first render, in ajax call we set some variable representing that data was loaded as boolean true and second render call shows wanted final children component.