Build a user interface with React

React

  • A library to build user interfaces

  • Facebook

  • Component-based

  • Popular

Component

A component is a part of the UI

Root

Search

bar

Filters

Houses list

House

Description

Price

import React, { Component } from 'react'

class House extends Component {
    state = { }
    render() { 

    }
}

React Element

Virtual DOM

  • "Virtual" representation of the DOM in memory

  • Synced with the "real" DOM by ReactDOM

Real DOM

Virtual DOM

DOM Element

React Element

React

reacts to change

Project: Pokeshop

2

+

-

3

+

-

5

+

-

0

+

-

0

+

-

Total

10

Environment setup

Tools

Must Have extensions

  • Simple React Snippets

  • Prettier

Create React App

  • One Dependency: There is just one build dependency. It uses Webpack, Babel, ESLint, and other amazing projects

  • No Configuration Required

  • No Lock-In: You can “eject” to a custom setup at any time

├── node_modules/     # Installed necessary packages 
├── public/           # Static files
│   ├── favicon.ico
│   └── index.html
├── src/              # Application root
│   ├── components/   # Application components
│   │   ├── board.js
│   │   ├── game.js
│   │   └── square.js
│   ├── index.css
│   ├── index.js
│   ├── logo.svg
│   └── utils/        # Utility files
│       └── index.js
├── package.json
├── README.md
└── yarn.lock

4 directories, 12 files
 # Configuration files for Jest & Webpack
 # Polyfills for Promises and Object.assign()
 ├── config/
 │   ├── env.js
 │   ├── jest/
 │   │   ├── cssTransform.js
 │   │   └── fileTransform.js
 │   ├── paths.js
 │   ├── polyfills.js
 │   ├── webpack.config.dev.js
 │   └── webpack.config.prod.js
 ├── node_modules/     # Installed packages necessary for Create-React-App
 ├── package.json
 ├── public/
 │   ├── favicon.ico
 │   └── index.html
 ├── scripts/          # Exposed React Scripts
 │   ├── build.js
 │   ├── start.js
 │   └── test.js
 ├── src/
 │   ├── components/
 │   │   ├── board.js
 │   │   ├── game.js
 │   │   └── square.js
 │   ├── index.css
 │   ├── index.js
 │   ├── logo.svg
 │   └── utils/
 │       └── index.js
 └── yarn.lock

8 directories, 21 files

Our first component: PokeCounter

2

Increment

"Hello World"

import React from "react";
import ReactDOM from "react-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import PokeCounter from "./components/pokeCounter";

ReactDOM.render(<PokeCounter />, document.getElementById("root"));

index.js

import React, { Component } from "react";

class PokeCounter extends Component {
  render() {
    return <h1>Hello World</h1>;
  }
}

export default PokeCounter;

pokeCounter.jsx

Multiple children

import React, { Component } from "react";

class PokeCounter extends Component {
  render() {
    return (
      <React.Fragment>
        <h1>Hello World</h1>
        <button>Increment</button>
      </React.Fragment>
    );
  }
}

export default PokeCounter;

Necessary to have a parent element!

Embedding expressions

import React, { Component } from "react";

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

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

  render() {
    return (
      <React.Fragment>
        <h1>{this.formatCount()}</h1>
        <button>Increment</button>
      </React.Fragment>
    );
  }
}

export default PokeCounter;

Setting attributes

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

Introduction to React

By zolani

Introduction to React

October 2019

  • 617