React

Overview

  • Front-end tool to render interactive web user interfaces.

  • Declarative immutable views.

  • Component-based: embed HTML-like markup within JavaScript using JSX XML-like syntax (violates separation of concerns).

  • From Facebook.

  • Note that updated docs on are on react.dev. Watch out for legacy docs.

React Hello World

Hello World react app. Code in hello.html.

  • <h1>Hello, world!</h1> is an example of JSX embedded within JavaScript.

  • text/babel mime-type used to specify use of Babel, which allows supporting newer JavaScript features in browsers using syntax transformers. Used for translating embedded JSX.

Building JavaScript for the Browser

  • Example uses a self-contained HTML file which translates at runtime. Not recommended for production.

  • Modern JavaScript development for the browser typically uses a build step on the server to build the artifacts deployed in the browser.

    Package Manager

    Examples are npm or yarn (yarn is from Facebook; better reproducibility and performance than npm).

    Bundler

    Allows writing modular code with module inclusion directives like require. Bundle everything together to minimize HTTP requests. Examples: webpack, browserify and parceljs.

    Compiler

    Allows writing code in more modern (or alternate) dialects of JavaScript and have it compiled to dialect supported by browser. Examples: babel, typescript (from MS, used in angular), dart (from Google, in ng2), Elm.

JSX

const element = <h1>hello world</h1>;
  • <h1>...</h1> represents JSX, an extension to JavaScript syntax. It is not a JavaScript string; it is not HTML.

  • JSX is syntactically a JavaScript expression.

  • A single JSX expression can be written over multiple lines; recommend wrapping in parentheses to avoid automatic semicolon insertion pitfalls.

  • Can embed JavaScript within braces inside JSX: const msg = <h2>hello {user.firstName}</h2>.

  • JSX elements can have props properties (look similar to HTML attributes, but can also have non-string-values like Object or Function):

        const msg = <h2>hello {user.firstName}
                      <img src={user.avatarUrl}/>
    		</h2>
    

Components

Welcome. Code in welcome.html.

  • Can define JSX components using a JavaScript function which takes a single argument props object representing the properties the component is called with.

  • Properties are immutable during the lifetime of a component.

  • User-defined component names must start with upper-case character.

  • We are rendering a list of JSX elements.

  • Each JSX element in a list must have a key attribute which makes it easy for react to identify it.

Clashes between HTML and JavaScript Identifiers

Since React JSX attempts to look like HTML, but is actually merely syntactic sugar for JavaScript code, it is necessary to replace HTML identifiers which are identical to JavaScript reserved words:

  • Instead of the HTML class attribute, use the JSX/DOM className prop.

  • Instead of the HTML for attribute, use the JSX/DOM htmlFor prop.

See Props for more information about the props available for built-in components

Static Course Schedule Example

Static Course Schedule Display Code in schedule1.html.

  • Top-level <App schedule> component which renders a <Schedule schedule> component.

  • <Schedule schedule> component renders a table with a heading and rows of <CourseSchedule> components.

  • A <CourseSchedule schedule> renders a single course schedule row.

Static Schedule Form Example

Static Course Schedule + Form. Code in schedule2.html.

  • Top-level <App schedule> component now renders a <SearchableSchedule schedule> component instead.

  • <SearchableSchedule schedule> component renders a <SearchForm> component followed by a <Schedule> component.

  • <SearchForm schedule> component renders a select control for selecting a dept department and an input control to allow filtering by descr course description. The select control is pre-populated with All plus all unique dept in schedule.

  • <Schedule schedule> component is as in previous slide.

Course Schedule Filtering Example

Static Filtered Schedule Code in schedule3.html.

  • No change in example rendering, but <Schedule schedule dept descr> now allows filtering schedules based on added dept and descr props.

Form Values Example

Schedule with Form Values Initialized. Code in schedule4.html.

  • Added value prop to <select> and <input> widgets.

  • Cannot change <input> widget.

  • Note warning from react in console.

Dynamic Course Schedule Example

Fully Working Dynamic Schedule. Code in schedule5.html.

  • Added dept and descr state to <SearchableSchedule> component.

  • Pass value of dept and descr as props to both <SearchForm> and <Schedule> components.

  • Pass state change handlers deptChange and descChange down to <SearchForm> component.

  • The <SearchForm> component renders both the <select> and <input> widgets with a onChange handler which calls the change handler props with the target value.

React Components

  • A react component is not the same as a DOM element; the react component wraps the DOM element.

  • A react event is not the same as a DOM event; the react event wraps the DOM event.

  • With the react hooks API, all react components can be implemented using functions.

    Note: before hooks were added to the react API, stateful react components were implemented using JS classes, but such code is now regarded as legacy and will not be covered in this course.

  • The function for a component is called each time the component is rendered.

  • A component is rendered when first mounted in the DOM and re-rendered when any of its props or state constituents change.

  • The function implementing a component is simply a function with a Pascal-cased (AKA upper-camel-cased) name which takes a single props parameter and returns a rendering (usually JSX, but can also be a string or array of JSX) of the component.

React Hooks

  • The function implementing a component can access and update the state of a stateful component using the useState() hook.

  • The function can respond to side-effects using the useEffect() hook.

  • Other hooks include useContext(), useReducer(), useCallback(), useMemo() and useRef().

  • It is also possible to have user-defined hooks.

The useState() Hook

  • The hook is called with either an initial state value initValue or a function initFn which should return the initial state value when called.

        useState(initValue)
        useState(initFn)
    
  • Returns a pair [value, setValue] where value is the current value of the state constituent and setValue() is a function for updating the constituent.

  • The initial value initValue is used for initializing the state before the first render of the component; it is ignored for subsequent renders. Hence if initValue is expensive to compute, the computation can be done lazily by using the useState(initFn) form; initFn() will be called only before the first render.

  • The state can be updated using the second element setValue() of the return value.

  • Updating the state will re-render the component; without care, this could result in an infinite loop.

A Counter

Counter. Code in counter.html.

  • Initial render will set count to 0.

  • Clicking on + or - button will setCount(count + 1) or setCount(count - 1).

  • The setCount() call results in the component's state changing.

  • The state change results in a re-render.

  • In the re-render, the useState() call returns the current value of count.

An Async Counter

Update counter after a delay in Bad Async Counter. Code in bad-async-counter.html.

  • Each render gets its own copy of event handlers.

  • Each event handler captures its current environment in a closure.

  • Closure captures environment when function is defined, not when it is executed.

  • Counter is not updated until the timeout expires.

  • But update() handler captures count value at time the counter was last rendered.

  • Result is a sequence of multiple clicks between timeouts reduced to a single click.

  • Fix by using a functional argument to setCount() in Fixed Async Counter (code: fixed-async-counter.html). Function argument is current value of count within state.

Stale Closures

Display alert containing counter value after a delay in Alert Counter. Code in alert-counter.html.

  • Because doAlert() captures its environment at the time it is defined, the alert() shows the count at the time when the Show Delayed Alert button is clicked, not the value at the time the alert() is displayed.

  • Problem occurs because the doAlert() is using a stale closure.

Multiple Select and Add/Remove Components

Multiple Select and Add/Remove; multi-cities.html.

State vs Props

  • Component props are like immutable function arguments.

  • Component state is like the component's memory. It keeps track of the dynamic state of the component.

  • Keep a logical state constituent in only one place, usually in a common parent of all components which set/use it.

  • If state can be derived from props, then it is not state. (if the computation is expensive, then it can be cached using the useMemo() hook).

The useEffect() Hook

  • The useEffect() hook can be used to run an Effect after a render:

        useEffect(fn, depArray)
    
  • If useEffect() is called without depArray, then react will call function fn() after every render.

  • If depArray is empty, then fn() is called only after first render (similar to legacy componentDidMount() lifecycle handler for class-based components).

  • If depArray is specified as an array of values, then fn() is called only if some value in depArray is different from its value in the previous render.

  • If fn() returns a function, then that function is called before each subsequent render and when the component is unmounted. The returned function can specify cleanup.

  • useEffect() can be used to perform asynchronous tasks like fetching data, setting up a subscription, etc.

A Clock

Unmounted Clock

React Principles

  • Single source of truth. Do not maintain state of component in DOM as well as in react. Typically for managed components, DOM state is reflected immediately into react state using a onChange() handler.

  • Migrate state to common ancestor component. Pass down change handlers to component which will change the state.

  • Distinguish between props and state.

  • Asynchronous initialization should be done using useEffect().

  • Prefer composition over inheritance; i.e., do not make DangerButton a subclass of Button; instead have it contain a Button component.

Rules of Hooks

Only call hooks from the top-level of React function components or from the top-level of custom hooks.

  • Do not call hooks from inside loops, conditions or nested functions.

  • Do not call from regular JavaScript functions.

  • Implementation depends on hooks always being called in the exact same order.

These rules follow from the fact that React identifies hooks based on their static order within a function component.

Custom Hooks

  • Custom hooks can be used to encapsulate some code.

  • Custom hooks must have names starting with use followed by an upper case letter.

  • Custom hooks can call other hooks, but must follow the Rules of Hooks.

  • Multiple Select and Add/Delete components.

  • Code uses a custom hook to factor out the commonality between citiesUpdate() and selUpdate() in multi-cities.html.

Multiple Select and Add/Delete Components using Effects

Multiple Select and Add/Remove Components using Effects; code

  • Uses effect to resolve earlier bug.

  • Uses a custom hook containing an effect to log component lifecycle events.

React Component Lifecycle Events

React Hooks Lifecycle Diagram

React Context

  • A common problem with functional programming is that a function deep in the call tree needs access to a particular piece of data. Consequently, all intermediate functions will need to pass in that data even though they have no interest in that data.

    React has a similar problems with props, referred to as prop drilling.

  • Using react Contexts provide a solution.

  • Contexts allow a nested component to access data from an enclosing component without needing to drill the data through intervening components using props. That is, we can avoid props drilling.

The Context API

  1. Create a context using createContext(defaultValue).

        const ColorCtx = React.createContext('cyan');
    
  2. Specify the context as the context provider when rendering a subtree.

        <ColorCtx.Provider value={color}>
          ...
        </ColorCtx.Provider>
    
  3. Access the context in the consumer component:

        const value = React.useContext(ColorCtx);
        //use value in component
    

    The value will be that set by the enclosing context provider (if any). If there is no enclosing context provider, then it will be the defaultValue specified when creating the context.

Context Example

Element References

  • A Ref is a wrapper object which contains a mutable current field. This can be used to track mutable state across renders. Unlike component state, changes to the ref state does not cause a re-render.

  • A React component is not an HTML element. It is possible to get a reference to the underlying element using useRef().

  • Canvas Example with code in canvas.html.

    1. Use a Ref variable with initial value init using useRef(init).

      	const canvasRef = React.useRef(null);
      
    2. Initialize the Ref variable by referring to it using a ref prop when rendering the component.

      	//set canvasRef.current to refer to
      	//<canvas> DOM element
              <canvas ref={canvasRef}...>...</canvas>
      
    3. Use the .current property to access the actual element:

              const ctx =
      	  canvasRef.current.getContext('2d');
      

Clocked Counter

React Hooks Clocked Counter. Run using npm install followed by npm start; then point browser to http://localhost:2346/entry.html.

Sources:

React Elements

Blog entry.

  • An element is a plain object providing an immutable description of "a component instance or DOM node and its desired properties".

  • An element is not an instance. Instances are described by elements. React takes care of creating, updating and destroying instances.

  • JSX is merely syntactic sugar for React.createElement().

  • Element merely contains a type which is a String, Function or subclass of a React.Component or a react Fragment, props which is an Object and Children which is a list of elements.

References