Problem with reacts and setState (asynchronous)

1

I have a problem with react js and with setState in the documentation it says it is asynchronous. And the problem I have is that I am using a Select and depending on the value that I select, it makes the request with ajax to the database but since it is asynchronous the value is not sent when I click on an option the first time, if not until the next one click on any option

How do I send the updated value? I have seen that setState I can receive a second argument that is a callBack but I am not sure how to update the value.

       class HttpPeticion extends React.Component{
  constructor(props){
   super(props);
   this.state={lista:[],
              showData:false,showNodata:false,
              cantidadResultados:'',
              errorTipo:'',errorBool:false
            };
    }

 handlerData(data){

   if (typeof data=="undefined") return 0;

  let errorTipo=data.tipo;
  let errorBool=data.error;

  if(errorBool){
     this.setState({errorBool:data.error})
     this.setState({errorTipo:data.tipo})
  }
  else{
    let recordSize= data.records.length;
      if(recordSize<= 0) {
         this.setState({showData:false})//ocular resultados
         this.setState({showNodata:true})//muestra "no hay datos"
       }else{
        this.setState({showData:true});//mostrar resultados
        this.setState({showNodata:false})//ocultar "no hay datas"
        this.setState({lista:data.records});
      }
    this.setState({cantidadResultados:recordSize + ' Coincidencias' });
 }

 }


    componentWillReceiveProps(){
    axios.post(this.props.urlServer,{'tipo':this.props.tipo,'nombre':this.props.nombre})
      .then(res => {
         this.handlerData(res.data.data);
      })
      .catch(function (error) {
         console.log(error);
      });
}


render(){
  return (
      <div>
         <div>{this.state.cantidadResultados}  </div>
         <div className={this.state.showData ? '': 'hidden' }>
            <ResultadoBusqueda datos={this.state.lista} />
          </div>

           <div className={this.state.showNodata ? '' : 'hidden'}>
             <h1>No hay ningun resultado </h1>
           </div>

           <div className={this.state.errorBool ? '':'hidden'}>
                <p>Un error ha ocurrido conectado con el ser servidor intente refresar la pagina(f5), si el problema
                     persiste contacte con el administrador.<a href="#">Mas informacion</a>  </p>
                <small>{this.state.errorTipo}</small>
           </div>
      </div>
  );
}
}

class ResultadoBusqueda extends React.Component{
    render(){
       return(
           <table>
              <thead>
                 <tr>
                  <th>Cuenta</th>
                  <th>Nombre</th>
                  <th>Precio</th>
                 </tr>
               </thead>
             <tbody>
            {
                 this.props.datos.map((item)=>{
                    return(
                       <tr key={item.cuenta.toString()}>
                       <td>{item.cuenta} </td>
                       <td>{item.nombre}</td>
                       </tr>
                    )
                 })
                }
            </tbody>
            </table>
      );
    }

}

class BusquedaAlumno extends React.Component {
setField (e) {
   //this.checkInput(e.target.value);
  this.setState({[e.target.name]: e.target.value})
}

render() {
   return (
      <div>

      <input type="text"
        onChange={(e)=>this.setField(e)}
        onKeyUp={(e)=>this.setField(e)}
        name="valor1"
       />
       <select onChange={(e)=>this.setField(e)} value={this.state.value} name="combo">
        <option value="-1">Selecciones</option>
         <option value="1">1</option>
         <option value="0">0</option>
       </select>

             <div>{this.state.valor1}</div>
              <div>{this.state.combo}</div>
         <HttpPeticion tipo={this.state.combo} nombre={this.state.valor1} urlServer={"http://localhost/viaLacteaQueryBusquedaId.php"} />
       </div>
    );
  }

If you show me the data but have that little inconvenience with the select and the textbox

    
asked by Sergio Romero 29.12.2016 в 05:48
source

3 answers

2

You have to realize that if something does not fit into your development, you are basically doing something wrong. You also have a set of bad practices that you are carrying out:

  • HttpPeticion: an invisible component? I suppose you are only making requests to the server with this component, if so! You should create this component as a service that only deals with requests and simplify the use of urls.
  • It does not make sense that you first set values and then make the request. First you have to make the request and then agree to the answer to set or not the chosen value
  • Use string as property and vice versa e.target.name and name="valor1" , set a unique value for what will be the attribute name either in the state or by variables
  • Isolate actions so that your code is scalable, separate events from input of those from select you will never know when you have to apply more logic to your events

In conclusion to your question and for the reasons I have given you I would write your component in this way more or less depending on your needs

import HttpPeticion from 'services/HttpPeticion';

class BusquedaAlumno extends React.Component {
  componentWillMount() {
    this.setState({
      selectValue: '',
      inputValue: '',
    });
  }

  onInputChange() {
    this.setState({
      inputValue: e.target.value
    });
  }

  onSelectChange(e) {
    HttpPeticion.get('http://localhost/viaLacteaQueryBusquedaId.php', (data) => {
      this.setState({
        selectValue: e.target.value
        data: data
      });
    });
  }


  render() {
    const { inputValue, selectValue } = this.state;

    return (
      <div>
        <input type="text" onChange={this.onInputChange} value={inputValue} />

        <select onChange={this.onSelectChange} value={selectValue} >
          <option value="-1">Selecciones</option>
          <option value="1">1</option>
          <option value="0">0</option>
        </select>

        <div>{inputValue}</div>
        <div>{selectValue}</div>
       </div>
    );
  }
}
    
answered by 29.12.2016 / 13:35
source
1

The setState method of the class Component accepts a callback as the second parameter to be executed when the status has already been updated .

this.setState({ [e.target.name]: e.target.value }, () => {
  // estado actualizado, hacer algo
});

In the callback you can put any logic that depends on the success of the update of that state entry.

    
answered by 29.12.2016 в 12:26
1

In addition to the recommendations of @JoseAPL, there is a problem in the handler that updates the status, for each input or select that updates the state you are not actually updating the state, you are replacing it completely so in doing this.

setField (e) {
    this.setState({[e.target.name]: e.target.value})
}

you are replacing the whole state and leaving it only with the field that is updated at that moment, eliminating the previous field, the solution is to use Immutability Helpers from React.

First the bookshop matters

import update from 'react-addons-update'

Then define your handler in this way.

setField (e) {
    this.setState(update(
        this.state,
        {[e.target.name]: {$set: e.target.value}}
    ))
}

As a good practice always use Immutability Helpers to mutate the state.

    
answered by 29.12.2016 в 16:54