Jason Chen
Jason Chen

Reputation: 2577

Getting ReactJS to instantly change value based on textarea?

I have a textarea where users input a location. Then, onBlur, the value of the weather is set and the result is supposed to change based on whatever the users typed in. The code works as it should. However, only if users fire it twice.

var Duck = React.createClass({
  getInitialState:function() {
    return {
      deesfault: 'Houston, Texas',
      setting: true,
      main: '',
    }
  },

  componentDidMount:function() {
    return this.callthebase();
  },

  callthebase: function() {
    var selfish = this;
    $.get('http://api.openweathermap.org/data/2.5/weather?q='+this.state.deesfault+"&units=imperial&appid=~~appid~~", function(data){
    selfish.setState(data);
    });
  },

  changeit: function() {
    this.setState({setting: false});
  },

  setsetting: function() {
    this.callthebase();
    this.setState({deesfault: document.getElementById('section').value});
    this.setState({setting: true});
  },

  changesection: function() {
    if (this.state.setting) {
      return (<p onClick={this.changeit}>In {this.state.deesfault}</p>)}

    else { return (<textarea id="section" defaultValue={this.state.deesfault} onBlur={this.setsetting} />) }
    },

  render: function() {
    return (
      <div>
        {this.changesection()}
        <p>The weather is {this.state.main.temp}</p>
      </div>
    )
  }
});

As is, I would have to type in a location, blur out of it, and then come back in, activate it, and then blur it out again for the code to actually do what I want. This does not appear to be a problem when I use plain dummy text. But when I make an API call, this problem arises.

Upvotes: 0

Views: 157

Answers (3)

Galeel Bhasha
Galeel Bhasha

Reputation: 1895

the below changes should work

componentDidMount:function() {
let data = this.callthebase(this.state.deesfault);
this.setState(data)},

callthebase: function(newValue){
return $.get('http://api.openweathermap.org/data/2.5/weather?  q='+newValue+"&units=imperial&appid=~~appid~~", (data) => data);},

setsetting: function(){
  let oldValue = document.getElementById('section').value;
  let newValue = this.callthebase(oldValue);
  this.setState({deesfault: newValue, setting: true});
},

Upvotes: 1

Nicola Pedretti
Nicola Pedretti

Reputation: 5166

You are calling callthebase, then setting deesfault to the new value.

setsetting: function(){
  this.callthebase();
  this.setState({deesfault: document.getElementById('section').value});
  this.setState({setting: true});

},

changing it before calling callthebase will not solve your problem though because setState is called asynchronously:

from the documentation:

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.

what you could do is something like this:

setsetting: function(){
      var newValue = document.getElementById('section').value;
      this.callthebase(newValue);
      this.setState({deesfault: newValue, setting: true});
    },

and of course modify callthebase to take in the new value.

P.S. avoid assigning this to a variable to be able to use it inside a function, you can use arrow functions from ES6 instead :)

callthebase: function(newValue){
    $.get('http://api.openweathermap.org/data/2.5/weather?  q='+newValue+"&units=imperial&appid=~~appid~~", (data) => {
        this.setState(data);
    });
},

Upvotes: 2

anvk
anvk

Reputation: 1201

What about adding onChange property for your textarea:

_onChange: function(event) {
   var value = event.target.value;

   // process value and update state here
},

<textarea id="section" defaultValue={this.state.deesfault} onChange={this._onChange} />

Upvotes: 1

Related Questions