React Component

Architecture

Objectives

  • Pass state to child components as props

  • Define which components own state

  • Use stateless functional components

How Is State Shared?

  • State is always passed from a parent down to a child component as a prop

  • State should not be passed to a sibling or a parent

Who owns the state?

class App extends Component {
  render() {
    return (
      <div>
       <Navbar />
       <TicTacToe />
      </div>
    );
  }
}

Owns the state

Wants State

State Should Be Owned by 1 Component

class InstructorItem extends Component {
  constructor(props) {
    super(props);
    this.state = { 
      name: this.props.name,
      hobbies: this.props.hobbies
    };
  }
  render() {
    return (
      <div>
        <h3>{this.state.name}</h3>
        <h4>
         Hobbies: {this.state.hobbies.join(", ")}
        </h4>
      </div>
    );
  }
}

Bad Practice: Don't Do This

Stateless Functional Components

Components implemented using a function,

not a class

The function implements the render method only:

no constructor, no state

import React from 'react';

const Greeting = props => (
  <h1>Hello, {props.name}</h1>
);

export default Greeting;

Stateless Functional Component

Thinking In React

setState

Can Be Tricky

Objectives

  • Use a function as the first parameter to setState

  • Add a callback to setState to determine when the state is up to date

setState That Depends on Previous State

this.state = { counter: 1 };
this.setState({
  counter: this.state.counter + 1
});
this.setState({
  counter: this.state.counter + 1
});
Object.assign({},
  {counter: this.state.counter + 1},
  {counter: this.state.counter + 1},
  {counter: this.state.counter + 1},
);
this.setState({
  counter: this.state.counter + 1
});

setState is Asychronous

this.setState((prevState, props) => {
  return {
    counter: prevState.counter + 1
  };
});

Solution: Update Function

Rule: When a setState depends on previous

          state, use a function parameter

this.setState({name: "Tim"});
// Won't be updated yet
console.log(this.state.name);

setState is Asynchronous

this.setState({name: "Tim"}, () => {
  console.log(
    "Now state is up to date",
    this.state.name
  );  
});

React

DevTools

Colored

Boxes

Virtual

DOM

Objectives

  • Describe the virtual DOM

  • Define a synthetic events

  • Describe changes in React 16 (Fiber)

Virtual DOM

A data structure stored by React that tracks changes from one render state to the next

If something has changed from one render to the next, the browser's DOM is update (Reconciliation)

Reconciliation

App

Instructor

Instructor

Instructor

App

Instructor

Instructor

Synthetic Events

Supports all the native browser events, but provides a consistent API on all browsers

React 16

What's New In Fiber?

React 16

 render() {
   return [
     <div key='a'>First Element</div>,
     <div key='b'>Second Element</div>   
   ];
 }

Render can return an array of JSX elements or a string

React 16

Error Boundary

React 16

Fiber

Events

Objectives

  • Demonstrate an onClick event

  • Using bond functions vs inline callbacks

onClick

class ClickExample extends Component {
  constructor(props) {
    super(props);
    this.state = { name: "tim" };
  }
  render() {
    return (
      <div>
        <p>{this.state.name}</p>
        <button type="button"
          onClick={() => this.setState({name: "TIM"})}>
          UPPERCASE
        </button>
      </div>
    );
  }
}
class ClickExample extends Component {
  constructor(props) {
    super(props);
    this.state = { name: "tim" };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick(e) {
    this.setState((prevState, props) => ({
      name: prevState.name.toUpperCase()
    });
  }
  render() {
    return (
      <div>
        <p>{this.state.name}</p>
        <button type="button" onClick={this.handleClick}>
          UPPERCASE
        </button>
      </div>
    );
  }
}
render() {
  return (
    <div>
      <p>{this.state.name}</p>
      <button type="button" onClick={this.handleClick()}>
        UPPERCASE
      </button>
    </div>
  );
}

Common Mistake

The function will be invoked immediatley, not on the event

In Line Arrow Functions vs Bind

No noticeable performance benefits of using bind in the constructor

Forms

Objectives

  • Describe a controlled component vs uncontrolled

  • Handle a submit using onSubmit

Uncontrolled Component

 <input type="text" />

React is not aware of what the user is typing, the browser is in charge of the state

Controlled Component

 <input type="text" value={this.state.inputText}/>

React is now in control of the state via this.state.inputText, but the input can't be updated

Controlled Component With Update

 <input
   type="text"
   name="inputText"
   value={this.state.inputText}
   onChange={(e) => {
     this.setState({inputText: e.target.value})
   }}
/>

React is now in control of the state via this.state.inputText and the state can change via onChange

onSubmit

<form onSubmit={(e) => {
  e.preventDefault();
  const data = [...this.state.data,
                this.state.inputText];
  this.setState({data, inputText: ''});
}}>
  <input
     type="text"
     name="inputText"
     value={this.state.inputText}
     onChange={(e) => {
       this.setState({[e.target.name]: e.target.value})
     }}
  />
</form>

Common Mistake

<form>
  <input
     type="text"
     name="inputText"
     value={this.state.inputText}
     onChange={(e) => {
       this.setState({[e.target.name]: e.target.value})
     }}
  />
  <button
    onClick={ /* trying to handle submit here */ }
    type="submit"
  >
   SAVE
  </button>
</form>

A button's click is not the same as a submit, use onSubmit

refs

Objectives

  • Define a ref in react

  • Use a ref on an uncontrolled input component

refs

A direct reference to

a DOM element

Use Cases

From React Docs

  • Managing focus, text selection, or media playback

  • Triggering imperative animations

  • Integrating with third-party DOM libraries

Warning!

Do not use refs when the job can be done with React

You should not need direct DOM access for most tasks

ref Example

<form onSubmit={(e) => {
  e.preventDefault();
  // access to the form value:
  console.log(this.inputText.value);
}}>
  <input
     type="text"
     ref={(input) => this.inputText = input}
  />
</form>

Todo

Exercise

Todo

Exercise

Solution

Recipe App

With State

Your

Turn

Memory

Game

HINTS

const CardState = {
  HIDING: 0,
  SHOWING: 1,
  MATCHING: 2
};

Card States


let cards = [
  {id: 0, cardState: CardState.HIDING, backgroundColor: 'red'},
  {id: 1, cardState: CardState.HIDING, backgroundColor: 'red'},
  {id: 2, cardState: CardState.HIDING, backgroundColor: 'navy'},
  {id: 3, cardState: CardState.HIDING, backgroundColor: 'navy'},
  {id: 4, cardState: CardState.HIDING, backgroundColor: 'green'},
  {id: 5, cardState: CardState.HIDING, backgroundColor: 'green'},
  {id: 6, cardState: CardState.HIDING, backgroundColor: 'yellow'},
  {id: 7, cardState: CardState.HIDING, backgroundColor: 'yellow'},
  {id: 8, cardState: CardState.HIDING, backgroundColor: 'black'},
  {id: 9, cardState: CardState.HIDING, backgroundColor: 'black'},
  {id: 10, cardState: CardState.HIDING, backgroundColor: 'purple'},
  {id: 11, cardState: CardState.HIDING, backgroundColor: 'purple'},
  {id: 12, cardState: CardState.HIDING, backgroundColor: 'pink'},
  {id: 13, cardState: CardState.HIDING, backgroundColor: 'pink'},
  {id: 14, cardState: CardState.HIDING, backgroundColor: 'lightskyblue'},
  {id: 15, cardState: CardState.HIDING, backgroundColor: 'lightskyblue'}
];
this.state = {cards: shuffle(cards)};

Memory Game State

Your

Turn

Component

Lifecycle

Objectives

  • Describe the component lifecycle methods

  • Describe use cases for lifecycle methods

Lifecycle Methods

Mounting

constructor()

componentWillMount()

render()

componentDidMount()

Lifecycle Methods

Unmounting

componentWillUnmount

Lifecycle Methods

Updating

componentWillReceiveProps(nextProps)

shouldComponentUpdate(nextProps, nextState)

componentWillUpdate(nextProps, nextState)

render()

componentDidUpdate(prevProps, prevState)

Forcing Update

Updating

forceUpdate(callback)

Skips shouldComponentUpdate and forces a render.  Should be avoided in most cases.

Lifecycle Methods

Lifecycle Method Examples

componentWillUnmount

Example

const NUM_BOXES = 32;
class Boxes extends Component {
  constructor(props) {
    super(props);
    const boxes = Array(NUM_BOXES).fill()
      .map(this.getRandomColor, this);
    this.state = {boxes};

    this.intervalId = setInterval(() => {
      const boxes = this.state.boxes.slice();
      const ind = Math.floor(Math.random()*boxes.length);
      boxes[ind] = this.getRandomColor();
      this.setState({boxes});
    }, 300);
  }
  componentWillUnmount() {
    clearInterval(this.intervalId);
  }
}

componentDidMount

AJAX Example

Hacker News API

GET https://hacker-news.firebaseio.com/v0/topstories.json

[15300069,15298833,...15267532]

GET https://hacker-news.firebaseio.com/v0/item/15300069.json

{"by":"maguay",
 "id":15300069,
 "title":"Google signs agreement with HTC",
 "url":"https://www.blog.google/topics/hardware/google-signs-agreement-htc-continuing-our-big-bet-hardware/"
}

Your

Turn

Flag

App

REST Countries API

[ ...,
 {"name":"United States of America",
  "population":323947000, "latlng":[38.0,-97.0],
  "flag":"https://restcountries.eu/data/usa.svg"},

  {"name":"Mexico",

    "population":122273473,"latlng":[23.0,-102.0],

    "flag":"https://restcountries.eu/data/mex.svg"},
  ...

]

GET https://restcountries.eu/rest/v2/all

Flag

App

Solution