2 chap04
Jason Zhu edited this page 2022-01-10 22:53:49 +11:00

Chapter 4. How React Works

4.1 Page Setup

For browser to work with React, browser need to load at least 2 libraries React & ReactDOM (as shown below)

Simplest form of HTML for working with React

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>React Samples</title>
  </head>
  <body>
    <!-- Target container -->
    <div id="root"></div>

    <!-- React library & ReactDOM (Development Version)-->
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

    <script>
      // Pure React and JavaScript code
    </script>
  </body>
</html>

4.2 React Elements

A React element is a description of what the actual HTML DOM element should look like.

  • React element are instructions for how the browser should be created.

e.g. create a React element to represent an h1 using React.createElement

React.createElement("h1", { id: "recipe-0" }, "Baked Salmon");

Where:

  • 1st arg defines type of DOM element to create
  • 2nd arg is properties of element
  • 3rd/4th/following arg is children of this React element, can be a single text or other React element.

React element is converted into DOM element during rendering as shown below:

<h1 id="recipe-0">Baked Salmon</h1>

The react element returned from .createElement is a JS literal that tells React how to construct DOM element. If logged, it's as follow:

{
    $$typeof: Symbol(React.element),
    "type": "h1",
    "key": null,
    "ref": null,
    "props": {id: "recipe-0", children: "Baked Salmon"},
    "_owner": null,
    "_store": {}
}

Where:

  • properties (i.e. content of "props" except children) are added to the HTML tag <...> as attribute
  • child text is added as text within the element
  • structure of React element has fields: $$typeof, type, key, ref, props, _owner, _store.
    • type property of React element tells React what type of HTML or SVG element to create
    • props property is data and child elements required to construct a DOM element
    • children property is for displaying other nested elements as text

4.3 React DOM

  • After React element (JS literal) created, ReactDOM render React element in browser.
  • ReactDOM has render method. (shown below) ReactDOM.render(...) has 2 args:
    • 1st arg is React Element we want to render.
    • 2nd arg is target node to be rendered.
  • ReactDOM has all tools needed for rendering elements.
const dish = React.createElement("h1", null, "Baked Salmon"); // create a text element as child of `h1` element

ReactDOM.render(dish, document.getElementById("root")); // Render titlement element (h1) to DOM, hence add `h1` element to `div` with `id` of `root`

resulting following HTML

<body>
  <div id="root">
    <h1>Baked Salmon</h1>
  </div>
</body>

.render can render array since React16

const dish = React.createElement("h1", null, "Baked Salmon");
const dessert = React.createElement("h2", null, "Coconut Cream Pie");

ReactDOM.render([dish, dessert], document.getElementById("root")); 

4.3.1 Children

Objective: understand how to use props.children

Given a HTML DOM tree (unordered list) as shown below

<ul>
  <li>2 lb salmon</li>
  <li>5 sprigs fresh rosemary</li>
  <li>2 tablespoons olive oil</li>
  <li>2 small lemons</li>
  <li>1 teaspoon kosher salt</li>
  <li>4 cloves of chopped garlic</li>
</ul>

We can create React element using following:

const list = React.createElement(
  "ul",
  null,
  React.createElement("li", null, "2 lb salmon"),
  React.createElement("li", null, "5 sprigs fresh rosemary"),
  React.createElement("li", null, "2 tablespoons olive oil"),
  React.createElement("li", null, "2 small lemons"),
  React.createElement("li", null, "1 teaspoon kosher salt"),
  React.createElement("li", null, "4 cloves of chopped garlic")
);

The React element JS literal is as follow:

console.log(list);

{
    "type": "ul",
    "props": {
    "children": [
    { "type": "li", "props": { "children": "2 lb salmon" }  },
    { "type": "li", "props": { "children": "5 sprigs fresh rosemary"}  },
    { "type": "li", "props": { "children": "2 tablespoons olive oil" }  },
    { "type": "li", "props": { "children": "2 small lemons"}  },
    { "type": "li", "props": { "children": "1 teaspoon kosher salt"}  },
    { "type": "li", "props": { "children": "4 cloves of chopped garlic"}  }
    ]
    ...
    }
}

Where:

  • props.children is an element tree
  • Each list item is a child.

For more complex recipe to like HTML shown

<section id="baked-salmon">
  <h1>Baked Salmon</h1>
  <ul class="ingredients">
    <li>2 lb salmon</li>
    <li>5 sprigs fresh rosemary</li>
    <li>2 tablespoons olive oil</li>
    <li>2 small lemons</li>
    <li>1 teaspoon kosher salt</li>
    <li>4 cloves of chopped garlic</li>
  </ul>
  <section class="instructions">
    <h2>Cooking Instructions</h2>
    <p>Preheat the oven to 375 degrees.</p>
    <p>Lightly coat aluminum foil with oil.</p>
    <p>Place salmon on foil</p>
    <p>Cover with rosemary, sliced lemons, chopped garlic.</p>
    <p>Bake for 15-20 minutes until cooked through.</p>
    <p>Remove from oven.</p>
  </section>
</section>

We can create use React element via

React.createElement(
    "section", // type of DOM element
    { id: "baked-salmon " }, // properties (e.g. props) of element
    React.createElement("h1", null, "Baked Salmon"), // First child
    React.createElement( // Second child (i.e. the ul with contents)
        "ul",
        { className: "ingredients" },
        React.createElement("li", null, "2 lb salmon"),
        React.createElement("li", null, "5 springs fresh rosemary"),
        React.createElement("li", null, "2 tablespoons olive oil"),
        React.createElement("li", null, "2 small lemons"),
        React.createElement("li", null, "1 teaspoon kosher salt"),
        React.createElement("li", null, "4 cloves of chopped garlic")
    ),
    React.createElement( // Third child (i.e. section with content)
        "section",
        { className: "instructions" },
        React.createElement("h2", null, "Cooking Instructions"),
        React.createElement("p", null, "Preheat the oven to 375 degress."),
        React.createElement("p", null, "Lightly cost aluminum foil with oil."),
        React.createElement("p", null, "Place salmon on foil"),
        React.createElement("p", null, "Cover with rosemary, sliced lemons, chopped garlic."),
        React.createElement("p", null, "Bake for 15-20 minutes until cooked through."),
        React.createElement("p", null, "Remove from oven.")
    )
);

Where:

  • React use className to define the class attribute of an HTML element.

Constructing elements with data

React can let us to separate data from UI (e.g. data in array, while map array to React element using JS logic)

e.g. Store recipe data in array, then map it to ReactDOM of list

// Store recipe data in array
const items = [
    "2 lb salmon",
    "5 sprigs fresh rosemary",
    "2 tablespoons olive oil",
    "2 small lemons",
    "1 teaspoon kosher salt",
    "4 cloves of chopped garlic"
]

React.createElement(
    "ul",
    { className: "ingredient" },
    items.map((ingredient, i) =>
        React.createElement("li", { key: i }, ingredient)
    )
)

Where:

  • key property of React elements: React like each element to have a key property, which is used by React to update its DOM efficiently. Without this property, warning error Warning: Each child in an array or iterator should have a unique "key" prop. ... will show up.
  • Here we use array index (Check the syntax of Array.map) as unique key value of each ingredient (React element).

4.4 React Components

Component: parts used by react to construct UI (e.g. Buttons, List, Heading, etc.)

  • React component allow us to reuse same structure by fill them with different datas.
  • How to create React component: write a function that return a component (i.e. Functional Component, a good pattern).

e.g. Handwritten React element

function IngredientsList() {
    return React.createElement(
        "ul",
        { className: "ingredients" },
        React.createElement("li", null, "1 cup unsalted butter"),
        React.createElement("li", null, "1 cup crunchy peanut butter"),
        React.createElement("li", null, "1 cup brown sugar"),
        React.createElement("li", null, "1 cup white sugar"),
        React.createElement("li", null, "2 eggs"),
        React.createElement("li", null, "2.5 cups all purpose flour"),
        React.createElement("li", null, "1 teaspoon baking powder"),
        React.createElement("li", null, "0.5 teaspoon salt")
    );
}

ReactDOM.render(
    React.createElement(IngredientsList, null, null),
    document.getElementById("root")
)

It generate following HTML DOM

<IngredientsList>
    <ul className="ingredients">
        <li>1 cup unsalted butter</li>
        <li>1 cup crunchy peanut butter</li>
        <li>1 cup brown sugar</li>
        <li>1 cup white sugar</li>
        <li>2 eggs</li>
        <li>2.5 cups all purpose flour</li>
        <li>1 teaspoon baking powder</li>
        <li>0.5 teaspoon salt</li>
    </ul>
</IngredientsList>

We can achieve above by: 1. create a component to be reused; 2. parse data

// Define data
const secretIngredients = [
    "1 cup unsalted butter",
    "1 cup crunchy peanut butter",
    "1 cup brown sugar",
    "1 cup white sugar",
    "2 eggs",
    "2.5 cups all purpose flour",
    "1 teaspoon baking powder",
    "0.5 teaspoon salt"
];

// Define component
function IngredientsList() {
    return React.createElement(
        "ul",
        { className: "ingredients" },
        items.map((ingredient, i) =>
            React.createElement("li", { key: i }, ingredient)
        )
    );
}

// Render
ReactDOM.render(
    React.createElement(
        IngredientsList, { items: secretIngredients }, null),
    document.getElementById("root")
);

It rendered to following HTML DOM

<IngredientsList items="[...]">
  <ul className="ingredients">
    <li key="0">1 cup unsalted butter</li>
    <li key="1">1 cup crunchy peanut butter</li>
    <li key="2">1 cup brown sugar</li>
    <li key="3">1 cup white sugar</li>
    <li key="4">2 eggs</li>
    <li key="5">2.5 cups all purpose flour</li>
    <li key="6">1 teaspoon baking powder</li>
    <li key="7">0.5 teaspoon salt</li>
  </ul>
</IngredientsList>

4.4.1 React Componenets: A Historical Tour