React Fundamentals IV

Kay Ashaolu

Events

  • We are now to the point where we can learn how to incorporate events
  • How do we execute data when someone clicks on a particular button?
  • We use the event properties that you would customarily find in HTML

Example

import React from "react";
import ReactDOM from "react-dom";

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};
    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState(state => ({
      isToggleOn: !state.isToggleOn
    }));
  }
  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

Example

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

There's a lot going on

  • This code creates a single button that has state indiciating whether it is on or off
  • This state is toggled whenever the button is clicked
  • This behavior is achieved by a few lines of code in the example

Constructor

  • this.handleClick = this.handleClick.bind(this);
  • What is this doing?
  • Remember when I spoke about arrow functions and how it's important to use them?
  • This is why: if you do not do this, then refernces to this function outside of the class will not have access to the this variable
  • This line binds that function to the instance of the class in which it is caused

handleclick()

  • We define the event handler within the component that we are creating
  • This is best practice: continues with the idea that everyting related to the component is within the component
  • The function is setting the state to be the opposite of what it is currently

New setState Function

  • Note that we are using a different version fo the setState fucntion, that has a parameter called "state"
  • This is the proper way of accessing the current state in order to determine what the new state will be
  • Do not use this.state directly: unexpected results may occur
this.setState(state => ({
  isToggleOn: !state.isToggleOn
}));
	

The render function

  • Here we set our handleClick() function to be executed onClick
  • Note that there are no quotation marks in setting properties for React when you are setting it to an expression
  • This is correct: React will add quotes to the final DOM

Conditional Rendering

  • Now we are getting a handle of React
  • Its time to demonstrate some capabilities of React to give you a sense of what's possible
  • You can conditionally render different components

Example

class UserGreeting extends React.Component {
  render() {
    return (<h1>Welcome back!</h1>);
  }
}

class GuestGreeting extends React.Component {
  render() {
    return (<h1>Please sign up.</h1>);
  }
}

class Greeting extends React.Component {
  constructor(props) {
    super(props)
  }
  render() {
    if (this.props.isLoggedIn) {
      return <UserGreeting />;
    }
    return <GuestGreeting />;
  }
}
		

Example

class LoginButton extends React.Component {
  render() {
    return (
      <button onClick={this.props.onClick}>
        Login
      </button>
    );
  }
}
class LogoutButton extends React.Component {
  render() {
    return (
      <button onClick={this.props.onClick}>
        Logout
      </button>
    );
  }
}
		

Example

class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
    this.state = {isLoggedIn: false};
  }

  handleLoginClick() {
    this.setState({isLoggedIn: true});
  }

  handleLogoutClick() {
    this.setState({isLoggedIn: false});
  }

		

Example

  render() {
    const isLoggedIn = this.state.isLoggedIn;
    let button;
    if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />
    }
    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    );
  }
}

ReactDOM.render(
  <LoginControl />,
  document.getElementById('root')
);
    

Conditional Rendering Example

  • There's a lot going on
  • We'll go through this step by step
  • This also gives a good example of how components can nest within each other and how properties in a parent component can be passed down to its children

Greeting Component

  • The Greeting component dependent on the property isLoggedIn renders a different component
  • If isLoggedIn is true, render UserGreeting
  • If isLoggedIn is false, render GuestGreeting

LoginControl Component

  • Note the larger LoginControl Component also determines whether a LoginButton or a LogoutButton is created
  • The component also contains a Greeting component
  • Note the LoginControl Component connects the onClick event of both buttons to drive the state of the component
  • Also the LoginControl passes the current state to the Greeting via properties

Lists and Keys

  • One common functionailty is to have lists of objects driven by React
  • Since a list can be added to/subtracted from at any point, you do not know how many compoennts you will need beforehand
  • For React to be able to keep track of all of the components within a list, we'll need to specify a unique key
  • React uses that key to refer to a particular item in a list of components

Example

import React from "react";
import ReactDOM from "react-dom";

class ListItem extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    const value = this.props.value
    return (<li>{value}</li>);
  }
}
		

Example

class NumberList extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    const numbers = this.props.numbers;
    const listItems = numbers.map((number) =>
      <ListItem key={number.toString()}
                value={number} />
    );
    return (
      <ul>
        {listItems}
      </ul>
    );
  }
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);
		

Example Explained: ListItem

  • We define a component that comprises of just an element in the list
  • With React composing components out of other components is not only easy to do but encouraged
  • Enables the creation of a complex design using simple building blocks

Example Explained: NumberList

  • In the rendering of a NumberList, a number of ListItems are created
  • Note the use of the map() function that enables you to execute the same function over each element in a list
  • The result is saved in a constant, which is then added to the render function call

Key Attribute

  • If you are creating multlple instances of a component in the same array, its good to specify a key
  • A key gives React the ability to target specific instances

Questions?