Build a user interface with React

ECA React - November 28th 2018

Last time...

  • React

  • Virtual DOM

  • JSX

  • Create-react-app Webpack, Babel...

  • Component

Let's continue !

2

+

-

3

+

-

5

+

-

0

+

-

0

+

-

Total

10

Reset

Delete

Delete

Delete

Delete

Delete

class PokeCounter extends Component {
  state = {
    count: 1
  };

  formatCount() {
    return this.state.count === 0 ? "Zero" : this.state.count;
  }

  render() {
    return (
      <React.Fragment>
        <span className="badge badge-primary m-2" style={{ fontSize: 20 }}>
          {this.formatCount()}
        </span>
        <button className="btn btn-secondary btn-sm">Increment</button>
      </React.Fragment>
    );
  }
}

Rendering classes dynamically

class PokeCounter extends Component {
  state = {
    count: 1
  };

  formatCount() {
    return this.state.count === 0 ? "Zero" : this.state.count;
  }

  getBadgesClasses() {
    let classes = "badge m-2 badge-";
    classes += this.state.count === 0 ? "warning" : "primary";
    return classes;
  }

  render() {
    return (
      <React.Fragment>
        <span className={this.getBadgesClasses()}>{this.formatCount()}</span>
        <button className="btn btn-secondary btn-sm">Increment</button>
      </React.Fragment>
    );
  }
}

Rendering lists

class PokeCounter extends Component {
  state = {
    tags: ["tag1", "tag2", "tag3"]
  };

  render() {
    return (
      <React.Fragment>
        <ul>
          {this.state.tags.map(tag => (
            <li key={tag}>{tag}</li>
          ))}
        </ul>
      </React.Fragment>
    );
  }
}

Conditional rendering

class PokeCounter extends Component {
  state = {
    tags: ["tag1", "tag2", "tag3"]
  };

  renderTags() {
    if (this.state.tags.length === 0) {
      return <h1>No element to be rendered</h1>;
    }
    return (
      <ul>
        {this.state.tags.map(tag => (
          <li key={tag}>{tag}</li>
        ))}
      </ul>
    );
  }

  render() {
    return (
      <React.Fragment>
        {this.state.tags.length === 0 && "Please create a new tag"}
        {this.renderTags()}
      </React.Fragment>
    );
  }
}

Handling Events

class PokeCounter extends Component {
  state = {
    count: 1
  };

  /** [...] */

  incrementCount() {
    console.log("Incremented");
  };

  render() {
    return (
      <React.Fragment>
        <span className={this.getBadgesClasses()}>{this.formatCount()}</span>
        <button onClick={this.incrementCount} 
                className="btn btn-secondary btn-sm">Increment</button>
      </React.Fragment>
    );
  }
}
class PokeCounter extends Component {
  state = {
    count: 1
  };

  /** [...] */

  incrementCount = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <React.Fragment>
        <span className={this.getBadgesClasses()}>{this.formatCount()}</span>
        <button onClick={this.incrementCount} 
                className="btn btn-secondary btn-sm">Increment</button>
      </React.Fragment>
    );
  }
}

What happens when state changes?

Passing event arguments

class PokeCounter extends Component {
  state = {
    count: 1
  };

  /** [...] */

  incrementCount = (pokeball) => {
    console.log(pokeball);
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <React.Fragment>
        <span className={this.getBadgesClasses()}>{this.formatCount()}</span>
        <button onClick={() => this.incrementCount("my pokeball")} 
                className="btn btn-secondary btn-sm">Increment</button>
      </React.Fragment>
    );
  }
}

2

Increment

Composing components

2

+

-

3

+

-

5

+

-

0

+

-

0

+

-

PokeCounters

PokeCounter

Reset

Delete

Delete

Delete

Delete

Delete

2

Increment

1

Increment

2

Increment

3

Increment

2

Increment

import React, { Component } from "react";
import PokeCounter from "./pokeCounter";

class PokeCounters extends Component {
  state = {};

  render() {
    return (
        <div>
            <PokeCounter />
            <PokeCounter />
            <PokeCounter />
            <PokeCounter />
            <PokeCounter />
        </div>
    );
  }
}

export default PokeCounters;

pokeCounters.jsx

import React, { Component } from "react";
import PokeCounter from "./pokeCounter";

class PokeCounters extends Component {
  state = {
    counters: [
        { id: 1, value: 0 },
        { id: 2, value: 0 },
        { id: 3, value: 0 },
        { id: 4, value: 0 },
        { id: 5, value: 0 }
    ]
  };

  render() {
    return (
        <div>
            {this.state.counters.map(counter => <PokeCounter key={counter.id}/>)}
        </div>
    );
  }
}

export default PokeCounters;

pokeCounters.jsx

Passing data to components

  • Data can be passed through attributes

  • <PokeCounter key={counter.id} value={counter.value} anotherAttribute="a value I pass to my component"/>
  • You can then retrieve the data from a plain JavaScript object called props

  • key will not be passed as it is a special keyword used to identify elements in a list

pokeCounter.jsx

import React, { Component } from "react";
import PokeCounter from "./pokeCounter";

class PokeCounters extends Component {
  state = {
    counters: [
        { id: 1, value: 0 },
        { id: 2, value: 0 },
        { id: 3, value: 0 },
        { id: 4, value: 0 },
        { id: 5, value: 0 }
    ]
  };

  render() {
    return (
        <div>
            {this.state.counters.map(counter => 
                <PokeCounter 
                    key={counter.id} 
                    value={counter.value}
                />
            )}
        </div>
    );
  }
}

export default PokeCounters;
import React, { Component } from "react";

class PokeCounter extends Component {
  state = {
    value: this.props.value
  };

  /** [...] */

  incrementCount = () => {
    this.setState({ 
        value: this.state.value + 1 
    });
  };

  render() {
    return (
      <React.Fragment>
        <span 
            className={this.getBadgesClasses()}>
            {this.formatCount()}
        </span>
        <button 
            onClick={this.incrementCount} 
            className="btn btn-secondary btn-sm"
        >
        Increment
        </button>
      </React.Fragment>
    );
  }
}

export default PokeCounter;

pokeCounters.jsx

State

  • Local to the component
  • Other components cannot access it
  • Some components do not need a state object

Props

  • Passed to a component
  • Once passed to the component, it cannot be modified

VS

See you next wednesday!

React (2/5) - Multiple components, state, props

By zolani

React (2/5) - Multiple components, state, props

ECA React - November 28th 2018

  • 692