No site found for btvca-curriculum.herokuapp.com; using Bootcamp content.

Lifting State to Parents

  • React components can manage their own state
  • Often components need to communicate state to others
  • Siblings do not pass state to each other directly
  • State should pass through a parent, then trickle down

Boiling Point Calculator

function BoilingVerdict(props) {
  if (props.celsius >= 100) {
    return (
      <p>The water would boil.</p>;
    )
  }
  return (
    <p>The water would not boil.</p>
  )
}

Lifting State - Calculator Input

  • An element to collect input is needed
  • The input is passed to the BoilingVerdict Component
function Calculator (props) {

  const [temperature, setTemperature] = useState('')

  return (
    <fieldset>
      <legend>Enter temperature in Celsius:</legend>
      <input
        value={temperature}
        onChange={(evt) => {
          setTemperature(evt.target.value)
        }} />

      <BoilingVerdict
        celsius={parseFloat(temperature)} />

    </fieldset>
  );
}

CodePen

Lifting State - Another Input

  • The calculator should work for Celsius & Fahrenheit

What we want

function Calculator (props) {

  return (
    <div>
      <TemperatureInput scale="c" />
      <TemperatureInput scale="f" />
    </div>
  );
}

Extract TemperatureInput

function TemperatureInput (props) {
  const [temperature, setTemperature] = useState('')

  const scale = props.scale;
  return (
    <fieldset>
      <legend>Enter temperature in {scaleNames[scale]}:</legend>
      <input value={temperature}
              onChange={(evt) => {
                  setTemperature(evt.target.value)
                }
              }
      />
    </fieldset>
    );
  }
}

Lifting State - Passing State

  • The components must be kept in sync
  • Each TemperatureInput holds it's own state
  • Sibling components can not communicate directly
  • State can be moved to Calculator to achieve this

Remove State from TemperatureInput

function TemperatureInput (props) {


  /* Send changes to the parent */
  handleChange(evt) {
    props.setTemperature(evt.target.value);
    props.setScale(props.scale)
  }

  /* Use READ-ONLY Props instead of State */

  return (
    <fieldset>
      <legend>Enter temperature in {scaleNames[scale]}:</legend>
      <input value={props.temperature}
             onChange={this.handleChange} />
    </fieldset>
  );
}

Lifting State - Parent State

  • Children call setTemperature from props with new state
  • Parent updates state with setTemperature
  • Children re-render with new props

Parent Calculator Passes State to Children

function Calculator (props) {

    const [scale, setScale] = useState('c')
    const [temperature, setTemperature] = useState('')

    const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;

    const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;

    return (
      <div>
        <TemperatureInput
          scale="c"
          temperature={celsius}
          setScale={setScale}
          setTemperature={setTemperature}
        />

        <TemperatureInput
          scale="f"
          temperature={fahrenheit}
          setScale={setScale}
          setTemperature={setTemperature}
        />

        <BoilingVerdict
          celsius={parseFloat(celsius)} />
      </div>
    );
  }
}

CodePen

Lifting State - Live Example

See the Pen djrKLj by Joshua Burke (@Dangeranger) on CodePen.

Lifting State - Conclusions

  • A single "point of truth" holds the state
  • Components communicate state by lifting it up to a Parent
  • Child components use a Parent updater function to lift state up
  • State flowing down makes state changes simpler to debug
  • Props should be derived from State

Lab: Post Selector

Let's create a React component that consists of two main components; a list of posts, and a display box. These should be two seperate components. You will also need a parent component that renders both the list, and the display box.

Using state and props set up the page so that when you click on a post the cotent is rendered in the display box.

Hint: If you want to store your posts locally it might be easiest to create JSON files to represent the posts. Or you could just use JSONPlaceholder

Links