<info 340/>

Intro to React

Tim Carlson
Autumn 2024

Questions?

View of the Day

  • Hello React! (lecture)

  • JSX (code demo)

  • Components (code demo)

  • Props (code demo) [if time, or check video!]

ES 6 Modules

Modules are self-contained, isolated scripts that are able to run in their own namespace (without polluting the global environment). Modules can export values that may be imported and used by other modules.

 

Web pages load modules by including a script tag with the type="module" attribute.

<!-- load a script as a module -->
<script type="module" src="path/to/module.js"></script>

Live-Server

cd path/to/project
npx live-server .

where index.html is!

dot to serve entire folder

When an HTML page is opened with the file:// protocol, JavaScript cannot access system files. You need to run a local web server instead to use the http:// protocol.
You can do this with the live-server package

Access the webpage at http://localhost:8080/index.html

Stop the server by using ctrl+c in the command shell.

Importing

It is "possible" to import external libraries and make them available in your script from JavaScript (not HTML)

CommonJS (used by Node.js)

ES 6 Modules (used by browsers)

const util = require('java-util');

node version of "import"

global to refer
to the library

module library name

import { ArrayList } from 'java-util'; //named import

module library name

Java

import java.util.ArrayList;

module name

variable to import

variable to import

Python

from java-util import ArrayList

Exporting Values

export variables, functions, and classes to be available for other modules to import.

/*** my-module.js ***/
export function foo() { return 'foo'; } //named export

export const bar = "bar"; //export a variable

//will not be available (a "private" function)
function baz() { return 'baz'; }
/*** index.js ***/
//example of named imports:
import {foo} from './my-module.js'; //single named import
import {foo, bar} from './my-module.js'; //multiple named import
foo() //=> 'foo'
console.log(bar) //=> 'bar'

relative path to file (start with ./)
.js extension is implied by default in Node

Importing Options

Use the as keyword to "alias" a value.

Use import * syntax to import all values from a module.

/*** my-module.js ***/
export function foo() { return 'foo'; } //"named" export

//provide an "alias" (consumer name) for value
export { bar as yourBar };
/*** index.js ***/
import { yourBar } from './my-module.js'; //import value by name
yourBar() //=> 'bar'

import { bar } from './my-module.js'; //error, no value `bar` exported

//provide "alias" for value when importing!
import {foo as myFoo} from './my-module.js';
myFoo(); //=> 'foo'

//import everything that was exported
//loads as a single object with values as properties
import * as theModule from './my-module.js'; 
theModule.foo(); //=> 'foo'
theModule.yourBar(); //=> 'bar'

Default Exports

Each module can have a single default export, which provides a shortcut when importing.

/*** my-module.js ***/
export default function sayHello() {
    return 'Hello world!';
}
/*** index.js ***/

//default import can assign own alias without needing name!
//think: "import {default as greet} from './mymodule.js'"
import greet from './my-module.js';

greet(); //=> "Hello world!"

Be careful about whether an export is named or default!

External libraries especially are not consistent.

When to export?

  • Only export a value if it must be used by another module. When in doubt, keep values private.
     
  • In general, prefer named exports. This makes it easier to export additional values later if needed.
     
  • If a module is designed around a single value or function (e.g., a single React Component), make it a default export. A single exported value isn't necessarily a default export!
  • Dynamically generate and interact with the DOM
     

  • Organize the DOM into User Interface "Components" for easy page design
     

  • Efficiently make changes to the rendered DOM (see here)

Ethical Consumption of Libraries?

Ethical Consumption of Libraries?

Creating DOM Elements

//DOM - element to show
const msgElem = document.createElement('h1');
msgElem.id = 'hello';
msgElem.classList.add('myClass');
msgElem.textContent = 'Hello World!';





//show the content in the web page 
//(inside #root)
document.getElementById('root').appendChild(msgElem);

Hello React

//React - element to show
const msgElem = React.createElement(
  //html tag
  'h1',
  //object of attributes
  { id: 'hello', className: 'myClass' },
  //content
  'Hello World!'
); 

//Create a "React root" out of the `#root` elemment
//then render the React element at that root
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(msgElem)

can't use "class" since a keyword

React can be used to create and render DOM elements.

React v18 (March 2022)

JSX

An XML syntax extension for the JavaScript language. You define React elements in a way that looks like HTML!

//JSX - element to show
const msgElem = <h1 id="hello" className="myclass">Hello World</h1>;





//Create a "React root" out of the `#root` elemment
//then render the React element at that root
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(msgElem)

shortcut syntax for React.createElement()

Transpiling with Vite

Since JSX is not actually valid JavaScript, we need to "translate" it into real JavaScript, called transpiling.

 

There are a number of tools that can do this work; we'll be using a build tool called Vite.js

Vite Dev Server

Vite provides a development server which will:

  • Automatically transpile React code into pure JavaScript
  • Manage module dependencies, including external libraries
  • Show build and syntax errors in the console
  • Automatically reload the page (replaces live-server)!
# Make sure you are in the project directory
cd path/to/project

# Install dependencies for existing project (installs vite)
npm install

# Run the development server script
npm run dev

JSX

Elements defined using JSX can include children.

const headerElem = (
  <header>
    <h1>Hello world!</h1>
    <p>This is a fine demo</p>
  </header>
);

//values need to have a "single" parent
const invalidCode = (
  <p>First sentence</p>
  <p>Second sentence</p>
)

const validCode = (
  <> {/* a fragment: a parent that won't be rendered */}
    <p>First sentence</p>
    <p>Second sentence</p>
  </>
);

use parentheses for JSX on multiple lines

a comment in JSX!

Inline Expressions

Use {} to include JavaScript expressions in the JSX. These expressions will be evaluated and inserted into the element's "HTML".

//Can include JavaScript expressions in React elements
const message = "Hello world!";
const element2 = <h1>{message}</h1>;


//Can include arbitrary expressions
const element = (
  <p>
    A leap year has {(365 + 1) * 24 * 60} minutes!
  </p>
);

//Can use inline expressions in attributes
const imgUrl = 'path/to/my_picture.png';
const pic = <img src={imgUrl} alt="A picture" />;

replace with expression (value)

use parentheses for JSX on multiple lines

React elements
must be closed

DEMO 1

Example 1
//JSX - element to show
const msgElem = <h1 id="hello" className="myclass">Hello React</h1>;

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(msgElem);
<!-- style.css -->

.myclass {
    font-family:Arial, Helvetica, sans-serif;
}

DEMO 2

//inside main.js
onst content = (
    <header>
      <h1>Hello world!</h1>
      <p>This is a fine demo</p>
    </header>
  );

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(content);

When put in line breaks to make the JSX readable, you need to put the whole thing in () so that ';' aren't assumed and entered for you 

DEMO 3

// Example 3
const content = (
    
    <div>
        <header>
            <h1>Hello world!</h1>
        </header>
        <main>
            <p>This is the main section</p>
        </main>
    </div>
);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(content);

DEMO 4

// Example 4 - inline examples 
const myTitle = "Hello Inline React";
const imgURL = './img/puppy.jpg';

const content = (
    
    <div>
        <header>
            <h1>{myTitle.toUpperCase()}</h1>
        </header>
        <main>
            <p>This is the main section</p>
            <p> A leap year has {(365 + 1) * 24 * 60} minutes!</p>
            <img src={imgURL} alt="a cute puppy"></img>

        </main>
    </div>
);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(content);

React Components

React lets us describe the page in terms of UI components, instead of HTML elements.

 

React Components

React lets us describe the page in terms of UI components, instead of HTML elements.

In effect, we will create our own XML Elements!

<App>
  <HomePage>
    <Header />
    <SearchBar />
    <EmployeeList>
      <EmployeeListItem person="James King" />
      <EmployeeListItem person="Julie Taylor" />
      <EmployeeListItem person="Eugene Lee" />
    </EmployList>
  </HomePage>
  <EmployeePage>
    <Header />
    ...
  </EmployeePage>
</App>

React Components

We define components as functions that return the DOM elements to be rendered

//declare a function to define a component
function HelloMessage(props) {

  
  //this function returns the elements (JSX)
  //that make up the component
  return (
     <h1>Hello World!</h1>
  );
}

//"call" function to create a new element value!
const msgElem = <HelloMessage />;

//show the content in the web page (inside #root)
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(msgElem)

what is rendered when
component is shown

our own HTML tags!

Capitalize!

NEVER CALL A COMPONENT FUNCTION WITH ()

 

ALWAYS RENDER AS A COMPONENT WITH <>

Demo example 5

Create a component (function) called HelloMessage 

// Example 5
function HelloMessage() {

    let message = "Hello Everyone!";
    return <h1>{message}</h1>;

}

const content = <HelloMessage />;

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(content);

Composing Components

function HelloMessage(props) {
   return <p>Hello World!</p>;
}

function GoodbyeMessage(props) {
   return <p>See ya later!</p>;
}

function MessageList(props) {
   return (
      <div>
         <HelloMessage /> {/* A HelloMessage component */}
       	 <GoodbyeMessage /> {/* A GoodbyeMessage component */}
      </div>
   );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(msgElem)

Components can render other components ("call" functions to create new elements), and mix those with regular DOM elements

comments in JSX

Demo 6 

function HeaderComponent(props) {
    return (
        <div>
            <header>
                <h1>React Demo Header</h1>
            </header>
        </div>);
}

function HelloMessage(props) {
    return <li>Hello World!</li>;
}

function GoodbyeMessage(props) {
    return <li>See ya later!</li>;
}

function MessageList(props) {
    return (
        <div>
            <ul>
                <HelloMessage /> {/* A HelloMessage component */}
                <GoodbyeMessage /> {/* A GoodbyeMessage component */}
            </ul>
        </div>
    );
}

const content =
    <>
        <HeaderComponent />
        <MessageList />
    </>
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(content)

Component Modules

Components are usually defined in separate modules (files), and then imported by modules that need to use them.

/*** in App.js ***/

//import from other components; HelloMessage.js, Messages.js, etc
import { HelloMessage } from './Messages'

//declare a function component
export default function App(props) {
  return (
    <HelloMessage /> {/* render imported Component */}
  )
}
/*** in index.js ***/
import App from './App' //default import

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />)

Demo 7: App.js and index.js

// within the app.jsx file

import { HeaderComponent } from './HeaderComponent';
import { MessageList } from './MessageList';

export default function App(props) {

    return (
        <>
        <HeaderComponent/>
        <MessageList/>
        </>
    );
}
/*** main.jsx ***/
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

Demo 7: HeaderComponent.jsx

// Within the components/HeaderComponent.js

export function HeaderComponent(props) {
    return (
        <div>
            <header>
                <h1>React Demo Header</h1>
            </header>
        </div>);
}

Demo 7: component/Main.js

// within the components/MessageList.js

export function MessageList(props) {
    return (
        <div>
            <ul>
                <HelloMessage /> {/* A HelloMessage component */}
                <GoodByeMessage /> {/* A GoodbyeMessage component */}
            </ul>
        </div>
    );
}


function GoodByeMessage(props) {
    return <li>See ya later!</li>;
}

function HelloMessage(props) {
    
    return <li>Hello World</li>;
}

Properties (props)

//Passing a prop called `message` with value "Hello property"
const messageA = <MessageItem message="Hello property!" />;

//A component can accept multiple props
//This component takes in a `name` property as well as 
//a `descriptor` property
const userInfo = <UserInfo name="Ethel" descriptor="Aardvark" />;

//Passing a value as a prop using an inline expression
const secret = "Shave and a haircut";
const messageB = <MessageItem message={secret} />;

We specify attributes for a component (called "props") when we instantiate a component by specifying the XML attributes (key-value).

Props are the "input parameters" into a component!

Properties (props)

function MessageItem(props) {
   const message = props.message; //access the prop



    //can use prop for logic or processing
   const messageUpper = message.toUpperCase(); 

   return <li>{messageUpper}</li>; //render based on prop
}

ReactDOM.createRoot(document.getElementById('root'))
   .render(<MessageItem message="Be quiet" />)

Inside the Component function definition, all the passed in props are passed in as a single argument object (conventionally called props). This object is the collection of all of the attributes/arguments.

ALL props stored in this object

Demo 8: component/Main.js

export function MessageList(props) {
    return (
        <div>
            <ul>
                <HelloMessage msg="Hola Amigo!!!" isLoud={true}/> 
                <GoodByeMessage /> 
            </ul>
        </div>
    );
}


function GoodByeMessage(props) {
    return <li>See ya later!</li>;
}

function HelloMessage(props) {

    const {msg, isLoud} = props; // destructuring the props

    let text=msg;

    if (isLoud) {
        text=text.toUpperCase();
    }
    
    return <li>{text}</li>;
}

Properties (props)

//Pass an array as a prop!
const array = [1,2,3,4,5];
const suitcaseElem = <Suitcase luggageCombo={array} />;


//Pass a function as a prop (like a callback)!
function sayHello() { 
  console.log('Hello world!');
}
const greetingElem = <Greeting callback={sayHello} />;

Importantly, props can be any kind of variable! This includes arrays, objects and functions

Props and Composition

function MessageList(props) {
  //msgComponents will be an array of components!
  const msgComponents = props.messages.map((msgStr) => {
    const elem = <MessageItem message={msgStr} key={msgStr} />; //pass prop down!
    return elem
  }

  return (
    <ul>
      {/* An array of components renders as siblings */}
      {msgComponents} 
    </ul>
  );
}

const messagesArray = ["Hello world", "No borders", "Go huskies!"];

ReactDOM.createRoot(document.getElementById('root'))
   .render(<MessageList messages={messagesArray} />)

Props will often need to be "passed down" to child components. A common pattern is to map an array of prop values to an array of children components to render!

unique "id" for the element

Action Items!

Action Items!

  • Complete task list for Week 6 (all items!)

  • Problem Set 06 due Friday

    • Get it done early so you can focus on React!

  • Problem Set 07 due in 2 weeks

    • This is the biggest one!

    • Get started early; project draft 2 is due right afterwards

 

Next time: More React -- working with Components

info340au24-react-intro

By Tim Carlson

info340au24-react-intro

  • 322