React

Under the Hood

=>

http://tinyurl.com/adn-react

Prereqs

Javascript

React JS

npm

document API

 

Prereqs

Javascript

React JS

npm

document API

 

ASK QUESTIONS !!!

js/jsx syntax, npm commands, API specs, etc.

What do we know about React?

Key Elements of a React Application

Creating UI Elements

Rendering UI Elements


  const App = () => (
     <div>
       <p>Hello, world</p>
     </div>
  )
 
  ReactDOM.render(
    <App />,
    document.getElementById('root')
  );

HTML-like syntax that is transpiled into raw Javascript

Demystifying JSX

Demystifying JSX

  
  const Box = ({ children }) => (
    <div>
      {children}
    </div>
  )

  const App = () => (
    <Box>
        Hello, World!
    </Box>
  )

JSX

Demystifying JSX

  
  const Box = ({ children }) => (
    <div>
      {children}
    </div>
  )

  const App = () => (
    <Box>
        Hello, World!
    </Box>
  )

JSX


  var Box = function Box(_ref) {
    var children = _ref.children;
    return React.createElement("div", null, children);
  };

  var App = function App() {
    return React.createElement(Box, null, "Hello, World!");
  };

Javascript

What do we need?

  • Node - v9+
  • npm - v6+
  • Babel Transpiler (JSX -> JS)
    • Babel React JS plugins

Project Setup


  mkdir react && cd react

  npm init

  mkdir src/ && touch src/index.js

(scripts available in talk repo README.md )

Project Setup


  npm install --save-dev @babel/core

  npm install --save-dev @babel/cli

  npm install --save-dev @babel/plugin-transform-react-jsx

(scripts available in talk repo README.md )

Project Setup


  touch .babelrc

(scripts available in talk repo README.md )


  {
    "plugins": [
      [
        "@babel/plugin-transform-react-jsx"
      ]
    ]
  }

Add the following to your .babelrc

Project Setup

(scripts available in talk repo README.md )


  "scripts": {
    "build": "babel src -d lib"
  }

Add the following build script  to your package.json file

Testing Babel Setup

  
  const Card = ({ title, text }) => (
    <div>
      <h2>{title}</h2>
      {text}
    </div>
  );

  const App = () => (
    <div>
      <Card title="Card One" text="this is card one!" />
    </div>
  );

Add the following to components to your src/index.js file

  
  npm run build

Run the build script:

  
  {
    "plugins": [
      [
        "@babel/plugin-transform-react-jsx",
        {
          "pragma": "createElement"
        }
      ]
    ]
  }

Update .babelrc to remove the call to "React"

Testing Babel Setup

Webpage Setup


  touch index.html

  <!DOCTYPE html>
  <html lang="en" dir="ltr">
    <head>
      <meta charset="utf-8" />
      <title>react</title>
    </head>
    <body></body>
    <!-- USE OUR lib/index.js SCRIPT -->
    <script type="text/javascript" src="lib/index.js"></script>
  </html>

Boilerplate for our index.html file

createElement Usage


  var Card = function Card(_ref) {
    var title = _ref.title,
        text = _ref.text;
    return createElement(
        "div", 
        null, 
        createElement("h2", null, title), 
        text
    );
  };

  var App = function App() {
    return createElement(
        "div", 
        null, 
        createElement(
          Card, 
          {
              title: "Card One",
              text: "this is card one!"
          }
        )
    );
  };

createElement Outline

  
 const createElement = (
   nodeType,  // String / Function
   props, // Object
   child1,
   child2,
   child3,
   ...,
   childX
  ) => {

    // TODO: create virtual DOM element
  }

What is createElement creating?

A new virtual DOM node.

(An object that represents the contents of  an HTML element)

  
  <div>
    <p>Hello, world</p>
  </div>

JSX

  
  createElement("div", 
                 null, 
                createElement("p", 
                              null, 
                              "Hello, world"))

transpiles to...

which creates a virtual DOM node...

  { 
    nodeName: "div",
    props: null,
    children: [
      {
        nodeName: "p",
        props: null,
        children: [
          "Hello, world"
        ]
      }
    ]
  }

First Implementation of createElement

  
  const createElement = (
      nodeName, // String / Function
      props, // Object / null
      ...children // any
  ) => {
    return {
       nodeName: nodeName,
       props: props,
       children: children
    }
  }

What's next?

We're creating virtual DOM objects but aren't doing anything with them.

 

Need to render them to the real DOM

render Implementation

Look familiar?

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

Look familiar?

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

Let's rewrite our own version of ReactDOM.render

  
  /** vnode { nodeName, props, children } **/
  
  const render = vnode => {
    // create DOM node from vnode
  }

render Implementation

  
  const render = vnode => {

    // TODOS:
    
    // create an element using the document object

    // set attributes (props) of the newly created dom node

    // render the children of vnode

    // return the created dom element
    
  }
  
  const render = vnode => {

    // TODOS:
    
    // create an element using the document object
    let node = document.createElement(vnode.nodeName)

    // set attributes (props) of the newly created dom node
    for (prop in vnode.props)
        node.setAttribute(prop, vnode.props[prop])
      

    // render the children of vnode
    for(let i = 0; i < vnode.children.length; i++)
        node.appendChild(render(vnode.children[i]))

    // return the created dom element
    return node
    
  }

Render Edge Case 1

  
  // JSX
  <div>
    Hello, world
  </div>
   
  
  // JS
  createElement("div", null, "Hello, world");
   
  
  // Virtual DOM (result from createElement)
  {
    nodeName: "div",
    props: null,
    children: ["Hello, world"]
  }

Render Edge Case 2

  
  // JSX

  <Card title="Card!" text="Here is some text" />
   
  
  // JS
  createElement(Card, {
    title: "Card!",
    text: "Here is some text"
  });
   
  
  // Virtual DOM (result from createElement)
  {
    nodeName: Card,
    props: {
        title: "Card!",
        text: "Here is some text"
    },
    children: []
  }
  
  const render = vnode => {

    // TODOS:

    // handle text nodes

    // handle function components
    
    // create an element using the document object
    let node = document.createElement(vnode.nodeName)

    // set attributes (props) of the newly created dom node
    for (prop in vnode.props)
        node.setAttribute(prop, vnode.props[prop])
      

    // render the children of vnode
    for(let i = 0; i < vnode.children.length; i++)
        node.appendChild(render(vnode.children[i]))

    // return the created dom element
    return node
    
  }
  
  const render = vnode => {

    // TODOS:

    // handle text nodes
    if(typeof vnode === "string")
        return document.createTextNode(vnode)

    // handle function components
    if(typeof vnode.nodeName === "function")
        return render(vnode.nodeName({ 
                        ...vnode.props, 
                        children: vnode.children 
                      }))
    
    let node = document.createElement(vnode.nodeName)

    for (prop in vnode.props)
        node.setAttribute(prop, vnode.props[prop])
      

    for(let i = 0; i < vnode.children.length; i++)
        node.appendChild(render(vnode.children[i]))

    return node
    
  }

Example Use Case

  
  const Card = ({ title, text }) => (
      <div>
          <h2>{title}</h2>
          <p>{text}</p>
      </div>
  )

  const App = () => (
      <div>
          <Card title="Card One" text="this is card one!" />
      </div>
  )


  // render app to the document body
  document.body.appendChild(render(<App />))

Issue rendering children

  
  const Card = ({ children }) => (
      <div>
         {children}
      </div>
  )

  const App = () => (
      <Card>
         Hello, world
      </Card>
  )

Error walkthrough

  
  createElement("div", null, ["Hello, world"])

  {
    nodeName: "div",
    props: null,
    children: [["Hello, world"]] // <-- the issue
  }

When attempting to render our Card component we generate the following

...which returns the following virtual DOM

Bottom line: When rendering children, we will attempt to call render on a nested array

createElement Refactor

  
  const createElement = (
      nodeName, // String / Function
      props, // Object / null
      ...children // any
  ) => {
    return {
       nodeName,
       props,
       children: children.flat() // <-- the fix
    }
  }

Application Demo

State Management

Application state management is a big part of what the React library provides

1.) Access to our global state

2.) Ability to set the global state

3.) Upon updating the state, initiate a page re-render

 

Our Requirements:

What's left of React?

Class component support

Efficient Rendering / Diffing

Alternative state management techniques

Component life-cycle methods

Event  System

PropType System

Fragments

....

 

 

A LOT.

Questions?

Made with Slides.com