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

Description

Props and State are the two methods available to React to deal with immutable and mutable data within the application. This lesson will explain their uses and differences.



Component Props and State

  • Dynamic data that Components use fall into one of two categories
  1. Props:

    • Similar to arguments of a function
    • Are immutable once passed in
    • Can be passed down to children explicitely
  2. State:

    • Private data held within the Component
    • Can be updated using setState({someNew: 'data'}) or the updater from useState
    • Must be updated from the object that owns it
    • Can be passed down to children as Props
    • Can be updated by children by passing functions

Stateless Functional Components

  • At their most basic form Components are a lot like functions
  • They accept input from their props and return HTML snippets as React Elements
  • Any function that accepts one argument (props) and returns JSX is valid
  • Stateless functions traditionally have no state of their own
<body>
  <div id="root"/>
</body>
<script>
  /* This is a perfectly valid React Component*/
  const HelloThere = (props) => {
    return <h1>Hello, { props.name }</h1>
  }

  ReactDom.render(<HelloThere name="Grace Hopper"/>,
    document.getElementById('root')
  )
</script>
<body>
  <div id="root">
    <!-- This is what the code would result in -->
    <h1>Hello, Grace Hopper</h1>
  </div>
</body>

All Props are Immutable

  • Neither Function nor Class components should mutate their Props
  • React requires Components to be 'Pure' toward their Props
/* Always returns the same JSX for given inputs */

function UserInfo (props) {
  return (
    <div className="UserInfo">
      <Avatar user={ props.user } />
      <div className="UserInfo-name">
        { props.user.name }
      </div>
    </div>
  );
}

Pure and Impure Functions

  • 'Pure' functions don't mutate inputs and always return the same output for the same inputs
/* This is a 'Pure' function */
/* It always returns the same output for given inputs */

function sum (first, second) {
  return first + second;
}
/* This is an 'Impure' function */
/* It can return different things based on the balance */

function deduct (bankAccount, amount) {
  bankAccount.balance = bankAccount.balance - amount;
  return bankAccount
}

Component State

Description

  • Data managed by the component that changes over time
  • Considered private data by default
  • Cannot be changed by the Parent
  • Has a set default value, can be null
  • Plain JavaScript Object

Rules

  • Never mutate the State directly
  • Always use this.setState() or the updater from useState
  • Limit access to State from children
  • If building from a prior value, pass an update callback function to this.setState()

Props vs State

State - Tick Live

  • Rememeber the Ticking Clock example

See the Pen React Clock Example by Joshua Burke (@Dangeranger) on CodePen.

State - Tick Code

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(
    element,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

State - Extract Component

Does this use component state?

/* Now we have a component */
function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}

/* Use the component in a function */
function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

State - Convert to Class

  • Convert the stateless function to a Class
/* From this */
function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}

/* To this */
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

State - Start the Clock

class Clock extends React.Component {
  constructor(props) {
    /* Make sure to call super in a constructor */
    super(props);
    /* Setting the initial state */
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <!-- Use the state instead of props -->
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

State - Manage the Clock

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

State - Working Clock

See the Pen Hello World in React by Joshua Burke (@Dangeranger) on CodePen.

State - Remember

  • Never update state directly, use setState({some: 'state'})
/* Not good */
this.state.comment = 'Hello';

/* Excellent */
this.setState({comment: 'Hello'});

Lab: Color Clicker

Let's create a new react project that has a button you can click to change the color of some text.

  • Create a new React component using npx create-react-app
  • Change your App component from a stateless functional component into a stateful class based component
  • Render a header with blue text, and a button that says "Change Color"
  • Using the state make it so that when you click the button the text changes to red
  • When you click the button again the text should change back to blue

State - Updates can be Async

  • Calling setState() schedules an update
  • React may batch those updates together for performance
  • If you use a prior value to calculate the state, pass a callback function
/* Incorrect */
this.setState({
  counter: this.state.counter + this.props.increment,
});

/* Super Great */
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

State - Updates are Merged

  • When state has many properties, update each separately
  • This allows for independent property merges
  • The merge is shallow
constructor(props) {
  super(props);
  this.state = {
    posts: [],
    comments: []
  };
}

componentDidMount() {
  fetchPosts().then(response => {
    this.setState({
      posts: response.posts
    });
  });

  fetchComments().then(response => {
    this.setState({
      comments: response.comments
    });
  });
}

State - Many Clocks

See the Pen Hello World in React by Joshua Burke (@Dangeranger) on CodePen.

Using Functional Component Syntax

Instead of creating a Component by extending the Component class we can write a function like this:

function StatelessComponent (props) {
  return <h1>Hello {props.name}</h1>
}

Then we can slot it into a stateful component like so:

class Stateful extends React.Component {
  constructor(props) {
    super(props);
    this.state = {name: "Bill"};
  }

  render() {
    return (
      <div>
        <StatelessComponent name={this.state.name} />
      </div>
    );
  }
}

We could also slot it into another stateless component and pass props directly to it:

function AlsoStateless (props) {
  return (
    <div>
      <StatelessComponent name="Bob" />
    </div>
  )
}