Client-Side Coding with React:

Props and State


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.




 Slides

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'})
    • 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 as props and returns JSX is valid
  • Stateless functions have no State i.e. state = {value: 'something'}
<body>
  <div id="root"/>
</body>
<script>
  /* This is a perfectly valid React Component*/
  const HelloThere = (props) => <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 */

const 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()
  • Limit access to State from children
  • If building from a prior value, pass an update 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'});

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.