Max T
Max T

Reputation: 1455

Input value isn't updating in React

I have two files: App.js that's handling state and Counter.js. Everything gets displayed, accept onChange doesn't update the values in the input. What am I doing wrong in the Counter? Should I handle it differently than using props?

import React, { Component } from 'react';

import Counter from './components/Counter';
import './App.css';

class App extends Component {
  state = {
    cost: 0,
    houseCost: 0,
    downPayment: 0,
    termOfLoan: 0,
    annualInterestRate: 0
  }
  handleChange(e) {
    this.setState({houseCost: e.target.houseCost});
  }
  handleCostChange = () => {
    this.setState(
      prevState => ({
        cost: prevState.cost += 1
      })
    );
  }
  render() {
    return (
      <div className="App">
        <Counter
          cost={this.state.cost}
          houseCost={this.state.houseCost}
          downPayment={this.state.downPayment}
          termOfLoan={this.state.termOfLoan}
          annualInterestRate={this.state.annualInterestRate}
          changeCost={this.handleCostChange}
          handleChange={this.handleChange}
        />
      </div>
    );
  }
}

export default App;

Counter.js

    import React from 'react';


const Counter = (props) => {

        return (
            <div className="counter">
                <input type="text" value={props.houseCost} placeholder="House Cost" onChange={() => props.handleChange}></input>
                <input type="text" value={props.downPayment} placeholder="Down Payment" onChange={() => props.handleChange}></input>
                <input type="text" value={props.termOfLoan} placeholder="Mortgage Period (years)" onChange={() => props.handleChange}></input>
                <input type="text" value={props.annualInterestRate} placeholder="Interest Rate" onChange={() => props.handleChange}></input>
                <button className="counter-action" onClick={props.changeCost}>Calculate</button>
                <span className="counter-score">{ props.cost }</span>
            </div>
            );
    }


export default Counter;s

Upvotes: 0

Views: 7658

Answers (3)

Mike
Mike

Reputation: 96

change handleChange to an arrow function. It is not bound to the class so an arrow function will remove the context or you can bind the function in the constructor.

handleChange = (e, key) => {
  this.setState({[key]: e.target.value});
}

this gives you a dynamic key so that you can use this handeChange function for all of your inputs and not have to write a new one.

also on your event in count.js isn't passing back the event.

onChange={(e) => props.handleChange(e, 'houseCost')}

Upvotes: 4

Eugene Dzhevadov
Eugene Dzhevadov

Reputation: 116

the issue is in your onChange handler. When you call this method you change the state only of one value "houseCost" and finally, the expected "e.target.value" is not correct. Try something like this:

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

And for each input like:

 <input type="text" name="houseCost" value={props.houseCost} placeholder="House Cost" onChange={() => props.handleChange} />

So, the input attribute "name" allows you to specify "event target name" and use them to change specific state value by "event target value" by one handler

Upvotes: 4

Ted
Ted

Reputation: 14927

You've got a couple problems, both in the handleChange function, and the way it's called from counter. See the example below:

class App extends React.Component {
  state = {
    cost: 0,
    houseCost: 0,
    downPayment: 0,
    termOfLoan: 0,
    annualInterestRate: 0
  }
  handleChange = (e, key) => {
    this.setState({[key]: e.target.value});
  }
  handleCostChange = () => {
    this.setState(
      prevState => ({
        cost: prevState.cost += 1
      })
    );
  }
  render() {
    return (
      <div className="App">
        <Counter
          cost={this.state.cost}
          houseCost={this.state.houseCost}
          downPayment={this.state.downPayment}
          termOfLoan={this.state.termOfLoan}
          annualInterestRate={this.state.annualInterestRate}
          changeCost={this.handleCostChange}
          handleChange={this.handleChange}
        />
      </div>
    );
  }
}




const Counter = (props) => (
  <div className="counter">
    <input 
      type="text" 
      value={props.houseCost}
      placeholder="House Cost" 
      onChange={e => props.handleChange(e, 'houseCost')}
    />
    <input 
      type="text" 
      value={props.downPayment}
      placeholder="Down Payment" 
      onChange={e => props.handleChange(e, 'downPayment')}
    />
    <input 
      type="text" 
      value={props.termOfLoan} 
      placeholder="Mortgage Period (years)" 
      onChange={e => props.handleChange(e, 'termOfLoan')}
    />
    <input 
      type="text" 
      value={props.annualInterestRate} 
      placeholder="Interest Rate" 
      onChange={e => props.handleChange(e, 'annualInterestRate')}
    />
    <button className="counter-action" onClick={props.changeCost}>Calculate</button>
    <span className="counter-score">{ props.cost }</span>
  </div>
);
   


ReactDOM.render(
  <App />,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="react"></div>

Upvotes: 3

Related Questions