Is it possible to have two states in one react component

- 1 answer

Ad

I'm trying to build a simple unit convertor to practice React.js. I want to be able to change the value of one unit eg: Kg, and have the other unit eg: lb to automatically change on the screen. Please see this website to give you an idea: http://www.convertunits.com/from/lb/to/kg

I have the following code, it renders but the units don't update. What I want to know is:

  • Is it even accurate for one component to have two states? 1 for Kg and another for lb
  • Or would they need to be sibling components? If so, how would they go about updating each other's states?
  • If it's possible to have the state for both units in the same component, what am I doing wrong here?

Thank you! (I have a simple express app to render the page)

import React from 'react';

export default class Converter extends React.Component {
    render() {
      return (
        <div className="convert">
            <Range />
        </div>
      );
   }
}


class Range extends React.Component {
  constructor(props) {
    super(props);
    this.state = { kg: null, lb: null };
}

kgClick() {
    this.setState({ lb: state.kg * 2.2046 });
}

lbClick() {
    this.setState({ kg: state.lb / 2.2046 });
}

render() {

  return (
        <div>
            <label> Kg: </label>
            <input type="number" name="Kg" onChange={this.kgClick} value={this.state.kg} />
            <label> Lb: </label>
            <input type="number" name="Lb" onChange={this.lbClick} value={this.state.lb} />
        </div>
    );
  }
}

Backend logic:

var express = require('express');
var app = express();

app.set('port', (9000));
app.set('view engine', 'jsx');
app.set('views', __dirname + '/views');
app.engine('jsx', require('express-react-views').createEngine({ transformViews: false }));

require('babel/register')({
    ignore: false
});

app.use('/', function(req, res) {
  res.render('index', "");
});

app.listen(app.get('port'), function() {});
Ad

Answer

Ad

Yes, it is perfectly valid (and often necessary) to have more than one state property in a React component.

Your main problem is that you are never passing your click event instance to the handler function. Therefore, that function has no way of knowing the value of the number input. Also, you need to update the state for both measurements in your function. This is because you are setting the value for your number inputs to equal the state of that value. When you change the number in the input, it will not actually change in the render of that input unless you also update the state. Finally, as mattclemens points out, you should make sure you are binding this correctly. Either bind it on the component instance (like I do below) or use ES6 arrow notation in your handler function.

With all of that in mind, your class will work if it looks something like this:

class Range extends React.Component {


constructor(props) {
    super(props);
    this.state = { kg: 0, lb: 0 };
}

kgClick(e) {
    var newLb = e.target.value * 2.2046;
    this.setState({ kg: e.target.value, lb: newLb });
}

lbClick(e) {
    var newKg = e.target.value / 2.2046;
    this.setState({ lb: e.target.value, kg: newKg });
}

render() {

  return (
        <div>
            <label> Kg: </label>
            <input type="number" name="Kg" onChange={this.kgClick.bind(this)} value={this.state.kg} />
            <label> Lb: </label>
            <input type="number" name="Lb" onChange={this.lbClick.bind(this)} value={this.state.lb} />
        </div>
    );
  }
}
Ad
source: stackoverflow.com
Ad