1
\$\begingroup\$

I am new to React and still getting a handle on props and state. I tried to adopt the example of lifting state from the React Docs and add the feature of different criteria by liquid type for evaluating these values.

Here is the JSBin version.

const liquidNames = {
  w: "Water",
  eth: "Ethanol"
};

var liquidInventory = {ethanol: {
  name: "Ethanol",
  freezing: -173.2,
  boiling: 173.1
}, "water": {
  name: "Water",
  freezing: 0,
  boiling: 212
}};

//test function to determine 'state of matter'
function LiquidState(props){
  var liquid = props.liquidType;
  if (props.temperature >= liquidInventory[liquid].boiling){
    return <p> Boiling {liquid}</p>
  } else if (props.temperature <= liquidInventory[liquid].freezing){
    return <p> Frozen {liquid}</p>
  } else {
    return <p> You have liquid {liquid}</p>
  }
}

//component to present the inputs and values of each water and ethanol
class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    this.props.onTemperatureChange(e.target.value);
  }

  render() {
    const temperature = this.props.temperature;
    const liquidType = this.props.liquidType;
    return (
      <div>
      <fieldset>
        <legend>Enter Temperature for {liquidType}: </legend>
        <input value={temperature}
          onChange={this.handleChange} />
          < LiquidState liquidType={liquidType} temperature={temperature} />
      </fieldset>
      </div>
    );
  }
}

//parent Temperature component that holds overall program state
class Temperature extends React.Component {
  constructor(props) {
    super(props);
    this.testWater = this.testWater.bind(this);
    this.testEthanol = this.testEthanol.bind(this);
    this.state = {
      temperature: '',
      liquidType: ''
    };
  }

  testWater(temperature) {
    this.setState({temperature})
  }

  testEthanol(temperature) {
    this.setState({temperature})
  }

  render() {
    const liquidType = this.state.liquidType;
    const temperature = this.state.temperature;
    return (
      <div>
        <TemperatureInput 
          temperature={temperature}
          liquidType={'water'}
          onTemperatureChange={this.testWater}  />
         <TemperatureInput 
          temperature={temperature}
           liquidType={'ethanol'}
          onTemperatureChange={this.testEthanol}  />
      </div>
    );
  }
}

ReactDOM.render(
  <Temperature />,
  document.getElementById('root')
);
\$\endgroup\$
2
\$\begingroup\$

Works well!

This:

const liquidType = this.state.liquidType;
const temperature = this.state.temperature;

Can be written as:

const { liquidType, temperature } = this.props;

This:

function LiquidState(props){
  var liquid = props.liquidType;
  if (props.temperature >= liquidInventory[liquid].boiling){
    return <p> Boiling {liquid}</p>
  } else if (props.temperature <= liquidInventory[liquid].freezing){
    return <p> Frozen {liquid}</p>
  } else {
    return <p> You have liquid {liquid}</p>
  }
}

Can be written as:

const LiquidState = ({ liquidType, temperature }) => {
  if (temperature >= liquidInventory[liquidType].boiling){
    return <p> Boiling {liquidType}</p>
  } else if (temperature <= liquidInventory[liquidType].freezing){
    return <p> Frozen {liquidType}</p>
  } else {
    return <p> You have liquid {liquidType}</p>
  }
}

It's not much, but it's been useful to me.

I think lifting the state up is mainly important, if you're actually using the state in the high level component or one of its child components.

In this case, the value in the input is passed on to every input. If you instead keep state local to the component, you can type different values for each liquid.

I've just made my own attempt to learn something myself. Maybe there's one more useful thing hiding in there:

var liquids = {
  ethanol: {
    name: "Ethanol",
    states: [
      {
        minTemperature: 173.1,
        maxTemperature: Infinity,
        state: 'Boiling'
      },
      {
        minTemperature: -173.2,
        maxTemperature: 173.1,
        state: 'Liquid'
      },
      {
        minTemperature: -(Infinity),
        maxTemperature: -173.2,
        state: 'Frozen'
      }
    ]
  },
  water: {
    name: "Water",
    states: [
      {
        minTemperature: 212,
        maxTemperature: Infinity,
        state: 'Boiling'
      },
      {
        minTemperature: 0,
        maxTemperature: 212,
        state: 'Liquid'
      },
      {
        minTemperature: -(Infinity),
        maxTemperature: 0,
        state: 'Frozen'
      }
    ]
  }
}

class TemperatureInput extends Component {
  constructor(props) {
    super(props)
    this.state = {
      temperature: 0
    }
  }

  onChangeTemperature(event) {
    this.setState({ temperature: parseFloat(event.target.value) })
  }

  renderLiquidState(liquid, temperature) {
    for(var i = 0; i < liquid.states.length; i++) {
      if(liquid.states[i].minTemperature < temperature && temperature <= liquid.states[i].maxTemperature) {
        return <span>{liquid.states[i].state} {liquid.name}</span>
      }
    }
  }

  render() {
    const { liquid } = this.props
    const { temperature } = this.state

    return (
      <div>
        <fieldset>
          <legend>
            Enter Temperature for {liquid.name}:
          </legend>
          <input
            value={temperature}
            onChange={this.onChangeTemperature.bind(this)}
          />

          {this.renderLiquidState(liquid, temperature)}
        </fieldset>
      </div>
    )
  }
}

class Temperature extends Component {
  render() {
    return (
      <div>
        <TemperatureInput liquid={liquids.water} />
        <TemperatureInput liquid={liquids.ethanol} />
      </div>
    )
  }
}
\$\endgroup\$
2
  • \$\begingroup\$ Excellent! Thank you very much. I like that arrow function and will take it on board. Thanks again for your time. \$\endgroup\$ – Cameron Apr 8 '17 at 21:47
  • \$\begingroup\$ The else keywords can be removed in LiquidState() \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ May 31 '19 at 19:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.