“During the Obama years, the Republican threshold for outrage was at ground level; now it’s so high that it’s lost in space. Back then, House Republicans created a special committee and spent more than two years investigating the deaths of four Americans in Benghazi, Libya. Now, Republicans resist any House attempts to investigate Trump’s mishandling of the coronavirus — or his handling of nearly $3 trillion in stimulus. All the House Republicans voted last week against creating a subcommittee to track federal coronavirus spending.”

— Max Boot, in The Washington Post

React Notes

Front-end web framework notes — React 17

React Notes

These are my React notes, covering React 17. React native development is not included here. If you find a mistake, please let me know.

The example code uses a new notation I am developing. More on that soon.

This page includes a two-column print style. For best results, print in landscape, apply narrow margins, change the Scale setting in your browser’s print options to 70%, and enable background graphics. Firefox and Chrome each have their own set of printing bugs, but one of them usually works.

Contents

create-react-app

create-react-app or CRA is an npm package from Facebook that creates and configures React projects. This single dependency installs and manages a number of other packages, including:

  • Babel, which is used to transpile JSX and newer JavaScript syntax into browser-ready JavaScript;
  • Webpack, which is used to manage module exports and imports, and to bundle imported code into a small number of files that produce fewer requests. It also produces source maps, which correlate transpiled, minified, and bundled code in the browser with unprocessed code, for display when debugging;
  • Jest, which is used to run tests.

If it becomes necessary to configure these packages directly, CRA can eject the project, converting it to a conventional installation with discrete dependencies. Once ejected, the project cannot be managed again with CRA.

Creating a project

To create project name within folder name:

npx create-react-app name

Running CRA with npx ensures that the latest version is used. The --template switch can be added to select common project configurations:

cra-template
The default template.
cra-template-typescript
Creates a TypeScript project.
cra-template-pwa
Creates a Progressive Web App project.
cra-template-pwa-typescript
Creates a Progressive Web App project with TypeScript.

Many third-party templates are distributed by npm.

Running the development build

To start the development server and run the development build:

cd name
npm start

By default, the development build is served to http://localhost:3000/. In most cases, the page reloads automatically when code is updated.

CRA configures the project with ESLint, which displays warnings in the console that runs npm start, in the VS Code Problems tab, and in the Console tab within the browser DevTools. Specific warnings can be disabled by adding rules properties to the eslintConfig block in package.json:

"rules": {
  "no-unused-vars": "off"
}

This disables warnings immediately in VS Code. The warnings are not disabled in the browser until the development server is restarted.

Running tests

To run tests:

npm test

Deploying the project

To compile the production build:

npm run build

The build output is stored in the build/ folder, which receives copies of the files in public/. Bundled JavaScript and CSS files are stored in build/static/js/ and build/static/css/; these files are also listed within build/asset-manifest.json, which is compiled automatically. Webpack adds cache-busting hashes to the bundle filenames, and updates these automatically when the file content changes.

Development with CRA

Project structure

Files in the public/ folder are copied to the build/ folder at compile time. They are not minified, nor are cache-busting hashes added to their names. Unlike src/ files, they cannot be targeted with import; they are meant to be served directly, or referenced from other public/ files with the %PUBLIC_URL% environment variable, which is replaced at compile time with an absolute path:

<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />

This path is blank by default, so public files are served from the root of the domain. The path can be changed by adding a homepage entry to package.json:

"homepage": "https://www.anthemion.org/ogle/"

In JavaScript, the public path can be read from process.env.PUBLIC_URL.

CRA adds these files to public/, among others:

index.html
The default page for the app, which is served to the browser before being populated with React output.
manifest.json
A basic web app manifest, which stores Progressive Web App metadata to be used when the app is installed on a mobile device. The file is referenced by a manifest link in the index.html head.

The src/ folder contains index.js, which writes top-level component output to index.html. The folder also stores JavaScript and CSS files that are used to implement components, plus assets referenced by components. All JavaScript imports target files relative to the src/ folder, whether these are modules, CSS files, images, or other imports.

Importing modules

CRA configures Webpack to use ECMAScript module syntax for exports and imports.

Normally, Node.js interprets files with the JS extension as CommonJS modules. Projects that use ECMAScript modules are expected to use the MJS extension, or alternatively, to add:

"type": "module"

to the top level of the package.json file. This is not necessary in CRA projects, because module exports and imports are processed by Webpack. In fact, using the MJS extension in a CRA project will produce confusing compile-time errors like Uncaught TypeError: undefined is not a function and Can't import the named export 'jsxDEV' from non EcmaScript module.

Code-splitting

Webpack automatically code-splits modules that are loaded dynamically:

import("./Mod.mjs").then(aMod => {
  aMod.uStart();
  ...
});

If a component is loaded this way, it must be the default export of its module, and it must be wrapped with React.lazy. A function that performs the import is passed to React.lazy:

const Grid = React.lazy(() => import("./Grid.mjs"));

then the component itself can be nested within a Suspense component, which offers a fallback attribute that displays arbitrary JSX while the component loads:

const oGrid = (
  <Suspense fallback={<div class="FallLoad"></div>}>
    <Grid />
  </Suspense>
);

Importing CSS

src/index.css is a global CSS file that can be used to style any element. Webpack also supports file-specific CSS imports that resemble ECMAScript module imports:

import "./Nav.css";

The styles in this CSS are available to components defined in the referencing file. Webpack bundles imported CSS into a single file at compile time.

Importing other files

Webpack allows images and other files to be used with import. When an image is imported:

import ImgLogo from "./ImgLogoNav.png";

the file is added to the bundle, and a path is returned that can be used to reference it in JSX:

<img src={ImgLogo} alt="" />;

The import name can also be used to reference the bundled file in CSS:

nav div.Logo {
  background-image: url(./ImgLogo.png);
}

When imported files change, Webpack adds hashes to the file paths that bust browser caching.

It is also possible to import JSON data. The file content is parsed automatically and assigned to the import variable:

import Words from "./Words.json";

Webpack can be configured to import other formats, including XML and CSV.

JSX

JSX is a markup language that specifies page content declaratively. At compile time, Babel converts JSX blocks into React.createElement expressions, which later generate ReactElement instances. React uses these to update its virtual DOM, and ultimately, the browser content.

JSX resembles HTML, but it differs in many small ways. React uses the DOM API to update page content, so element attributes are set with DOM property names, not HTML attribute names. In particular, element classes are set with className, rather than class. Properties are generally named with camelCase, rather than all lowercase, so onclick becomes onClick. ARIA and HTML data attributes continue to use kebab case.

It is not possible to assign CSS strings to the style attribute in JSX; an object must be embedded. CSS properties are identified in this object with camelCased versions of the usual CSS property names:

const oCSS = {
  color: "white",
  backgroundColor: "black"
};

return <div style={oCSS}>...</div>;

Empty elements like br must be represented with self-closing tags, even though these are optional in HTML5:

<br />

JSX blocks are often parenthesized to avoid ASI problems:

return (
  <h2>Tasks</h2>
);

Embedded expressions

A JavaScript expression can be embedded in JSX by surrounding it with curly braces:

const oElID = (
  <div>Block {"ID" + oID}</div>
);

Many expression values are converted automatically to strings; React escapes these and other string values before embedding them. There is no need to type quotes when assigning strings:

<div id={oID}>

In fact, quoting the placeholder would cause the braces and the contained expression to be interpreted literally.

Expressions can return JSX, which is then embedded in the surrounding content. Along with the ternery operator, operators like && are sometimes used to embed conditional JSX expressions:

<section>
  <div className="CtAct">
    {oCt} active
  </div>
  {oCkWarn &&
    <div className="CtWarn">
      {oTextWarn}
    </div>
  }
</section>

Embedding an array causes each element to be embedded in sequence. Embedding an object causes an exception to be thrown.

The following values produce no page output when embedded:

  • true
  • false
  • null
  • undefined

Event handling

In HTML, an event handler is defined with a string that contains inlined JavaScript. The handler is invoked directly, within the string:

<button onclick="uHandReady()">Ready</button>

In JSX, the handler is not invoked directly; it is assigned by passing a function reference through a placeholder. Unlike HTML attributes, React events are named with camelCase:

<button onClick={uHandReady}>Ready</button>

The handler receives a SyntheticEvent instance when it is triggered. This object provides the same interface that a DOM event object would, but it is not the same type. The DOM event object can be obtained from the synthetic event’s nativeEvent property.

To cancel a button’s default behavior, the handler must call preventDefault. It is not enough to return false:

function uHandSubmit(aEvt) {
  aEvt.preventDefault();
  ...
}

If the handler is a method of the component class, it must be bound to the class instance, or this will be defined incorrectly when the handler is invoked through the reference. This can be done by overwriting class methods in the constructor, after wrapping them with bind:

class Btn extends React.Component {
  constructor(aProps) {
    super(aProps);
    this.props = aProps;

    this.uHandClick = this.uHandClick.bind(this);
  }

  uHandClick(aEvt) {
    ...
  }

  render() {
    return (
      <button onClick={this.uHandClick}>
        {this.props.Text}
      </button>
    );
  }
}

Handlers can also be wrapped with arrow functions, which capture this in a closure:

this.uHandClick = (aEvt) => this.uHandClick(aEvt);

The wrapper can be defined in the component render function, but this creates a new wrapper every time the component is rendered, which could affect performance:

<button onClick={(aEvt) => this.uHandClickNum(aEvt)}>

If a non-event argument is required, this may be unavoidable. If the handler is wrapped with an arrow function, the event object must be forwarded in the wrapper definition:

<button onClick={(aEvt) => this.uHandClickNum(aNum, aEvt)}>
  {aNum}
</button>

If it is wrapped with bind, this must be forwarded in the wrapper definition, but the event object can be ignored, since a bound function automatically forwards additional arguments to the wrapped function:

<button onClick={this.uHandClick.bind(this, aNum)}>
  {aNum}
</button>

React event handlers

Handlers can target events during the bubbling phase, or the capture phase. Commonly-used bubbling event handler properties are listed below. The same events can be intercepted in the capture phase by appending Capture to these property names.

Page events
  • onFocus
  • onBlur
  • onScroll
Form events
  • onChange
  • onInput
  • onInvalid
  • onReset
  • onSubmit
Text input selection events
  • onSelect
Mouse events
  • onClick
  • onContextMenu
  • onDoubleClick
  • onDrag
  • onDragEnd
  • onDragEnter
  • onDragExit
  • onDragLeave
  • onDragOver
  • onDragStart
  • onDrop
  • onMouseDown
  • onMouseEnter
  • onMouseLeave
  • onMouseMove
  • onMouseOut
  • onMouseOver
  • onMouseUp
  • onWheel
Touch events
  • onTouchCancel
  • onTouchEnd
  • onTouchMove
  • onTouchStart
Pointer events
  • onPointerDown
  • onPointerMove
  • onPointerUp
  • onPointerCancel
  • onGotPointerCapture
  • onLostPointerCapture
  • onPointerEnter
  • onPointerLeave
  • onPointerOver
  • onPointerOut
Keyboard events
  • onKeyDown
  • onKeyPress
  • onKeyUp
Clipboard events
  • onCopy
  • onCut
  • onPaste
CSS transition events
  • onTransitionEnd
CSS animation events
  • onAnimationStart
  • onAnimationEnd
  • onAnimationIteration
Media events
  • onAbort
  • onCanPlay
  • onCanPlayThrough
  • onDurationChange
  • onEmptied
  • onEncrypted
  • onEnded
  • onError
  • onLoadedData
  • onLoadedMetadata
  • onLoadStart
  • onPause
  • onPlay
  • onPlaying
  • onProgress
  • onRateChange
  • onSeeked
  • onSeeking
  • onStalled
  • onSuspend
  • onTimeUpdate
  • onVolumeChange
  • onWaiting
Other events
  • onError
  • onLoad

Components

React components are reusable structures that generate ReactElement instances, representing page output. Functions in the react-dom module translate these instances to DOM elements in the browser. react-native translates them to native controls in various desktop and mobile platforms.

React expects component names to be capitalized; names with lowercase initials are assumed to be DOM elements. Components are referenced in JSX much the way DOM elements are:

const oLinks = (
  <ul>
    <ItLink Addr="/sec1" Text="Section 1" />
    <ItLink Addr="/sec2" Text="Section 2" />
    <ItLink Addr="/sec3" Text="Section 3" />
  </ul>
);

Component definitions must be in scope for the referencing JSX. When their definitions are nested within objects:

const Graphs = {
  Bar: function (aProps) {
    ...
  },
  Pie: function (aProps) {
    ...
  }
};

components can be referenced with ‘dot’ notation:

<div>
  <Graphs.Bar />
  <Graphs.Pie />
</div>

Component names are always interpreted as class or function references, so component types can be selected conditionally by assigning a reference to a variable, and then using the variable name as a component. The name must be capitalized, however:

function DispGraph(aProps) {
  const Graph = aProps.CkPie ? Graphs.Pie : Graphs.Bar;
  return (
    <div>
      <Graph />
    </div>
  );
}

In like manner, when components are passed to functions, the parameter names can be used as components:

function BtnLbl(Btn, Lbl) {
  return (
    <div>
      <Btn /><Lbl />
    </div>
  );
}

Function components

Components can be implemented as functions or classes. A function component resembles the render function found in a class component. It accepts a single props object argument that stores any prop attributes that were assigned when the component was invoked. It then returns a JSX expression:

function ItLink(aProps) {
  return <li><a href={aProps.Addr}>{aProps.Text}</a></li>;
}

or an array of JSX expressions, to be rendered in sequence within the component’s parent element:

function ItsLink(aProps) {
  return [
    <ItLink key="status" Addr="/status" Text="Status" />,
    <ItLink key="updates" Addr="/updates" Text="Updates" />,
    <ItLink key="settings" Addr="/settings" Text="Settings" />
  ];
}

If an array is returned, a sequence-unique key property should be assigned to each element. This value is not added to the component props. React uses keys to track changes within the element sequence, so element indices should not be used as key values if elements can be deleted, or if the sequence can be reordered.

Keys must be assigned in the array itself:

<ul>
  {oNums.map(o => <It key={o.toString()} Num={o} />)}
</ul>

They cannot be assigned in the embedded component’s render function.

The component can return null if it generates no page content. Like other render functions, function components should not produce side effects.

Class components

Class components subclass React.Component:

import React from "react";

class ItLink extends React.Component {
  constructor(aProps) {
    super(aProps);
    ...
  }

  render() {
    return (
      <li>
        <a href={this.props.Addr}>{this.props.Text}</a>
      </li>
    );
  }
}

Class instances are created and managed automatically by React, which passes the props object as a constructor argument. If a custom constructor is defined, it must forward this parameter to the base constructor, which stores it in the props class property.

The subclass must define a render method; this returns a JSX expression, an array of JSX expressions, or null, just as a function component would.

The constructor and the render method may be called at any time during the render phase, so they should not produce side effects. If the component must subscribe to an event published by another object, it should do so within the componentDidMount method.

Component props

Most attributes assigned to component instances:

<ItLink Addr="/" Text="Home" />

are combined into a props object that is forwarded to the component and used to configure its output. This object is frozen, so new properties cannot be added, and existing properties cannot be changed.

Props can be assigned any value, including functions and other objects. If an attribute is specified without a value, the corresponding prop will be set to true:

<BtnRadio CkDown />

It is better to specify these values explicitly, however:

<BtnRadio CkDown={true} />

The spread syntax can be used to forward the properties of an object as distinct props:

function ItLink(aProps) {
  return <li><Link {...aProps}/></li>
}

Default props

Ordinarily, if a prop’s attribute is not assigned when the component is invoked, it will be undefined in the component’s render function. Default values can be specified for one or more props by assigning an object to the component’s defaultProps property:

function Ship(aProps) {
  return <div>...</div>
}

Ship.defaultProps = {
  CdLoc: "PEND",
  CtFail: 0,
  CtRetry: 0
};

Prop type checking

React can perform run-time type checking on component props. Type checks are defined by assigning an object to the component’s propTypes property:

import PropTypes from "prop-types";

function StatWare(aProps) {
  return (
    <section>
      <h3>Area {aProps.NumArea}</h3>
      <div>{aProps.Notes}</div>
    </section>
  );
}

StatWare.propTypes = {
  NumArea: PropTypes.number,
  Notes: PropTypes.string
};

This object contains zero or more properties that associate prop names with specifiers imported from the prop-types module:

bool number string symbol object array func
Matches any value with the specified JavaScript type.
node
Matches any type that can be rendered by React, including numbers, strings, and elements, plus arrays or fragments of such.
element
Matches a ReactElement instance.
elementType
Matches a component reference.
instanceOf(class)
Matches an object that inherits, directly or indirectly, from class.
oneOf(vals)
Matches any of the values in array vals. These can vary in type.
oneOfType(types)
Matches any of the PropTypes specifiers in array types.
arrayOf(type)
Matches an array if all of its elements match the given PropTypes specifier.
objectOf(type)
Matches an object if all of its properties match the given PropTypes specifier.
shape(patt)
Matches an object if none of its properties conflict with object patt, which maps property names to PropTypes specifiers. Extra object properties are ignored, as are missing properties.
exact(patt)
Functions as shape, but fails to match objects that have extra properties. Missing properties are ignored, as before.

Note that complex specifiers like arrayOf can be used within other specifiers, such as oneOfType:

StatWare.propTypes = {
  // Allow a single number or an array of strings:
  Data: PropTypes.oneOfType([
    PropTypes.number,
    PropTypes.arrayOf(PropTypes.string)
  ]),
  NumArea: PropTypes.number,
  Notes: PropTypes.string
};

All specifiers define an isRequired property that acts as the same specifier, while also warning if the associated property is undefined:

StatWare.propTypes = {
  NumArea: PropTypes.number.isRequired,
  ...
};

Custom validation functions can be associated with props. Each function accepts a props object, a string containing the name of the prop being validated, and a string that gives the component name. The function should return an Error instance if the prop is invalid:

function Valid_PropNumShelf(aProps, aNameProp, aNameCompnt) {
  if (aProps.NumShelf
    && ((aProps.NumShelf < 1) || (aProps.NumShelf > NumShelfMax)))
    return new Error(aNameCompnt + ": Invalid shelf number")
}

StatWare.propTypes = {
  NumShelf: Valid_PropNumShelf,
  ...
};

Custom functions can also be passed to PropTypes.arrayOf or PropTypes.objectOf. These functions are invoked once for each array element or object property. They accept the props object, the index or key of the value being checked, the component name, an undocumented location parameter, and the full name of the property or element being checked.

Props that are not named in the propTypes object are not checked. For each check that fails, a warning is logged to the console. These checks are performed only within the development build. Default prop values are validated if and only if they are selected by the component.

Component state

Props are set by the component’s parent; they are immutable within the component, so it cannot trigger updates by modifying its own props. If a control changes in response to user input or another asynchronous event, it must do so by modifying its state. React.Component provides functionality that manages this state and the resultant updates.

A class component’s state is stored in an object referenced by the state property. This object can be assigned in the constructor, but direct updates are disallowed thereafter. Updates must instead be requested with the setState method, which is inherited from React.Component. This method eventually causes state to be updated, which causes render to be invoked:

class Page extends React.Component {
  constructor(aProps) {
    super(aProps);
    this.state = { CkAlert: false };

    this.uShow_Alert = this.uShow_Alert.bind(this);
  }

  uShow_Alert() {
    this.setState({ CkAlert: true });
  }

  uBoxAlert() {
    if (!this.state.CkAlert) return null;
    ...
  }

  render(aProps) {
    return (
      <div>
        {this.uBoxAlert()}
        ...
      </div>
    );
  }
}

When an object is passed to setState, it is merged with the current state data; properties in the new state overwrite those in the old, while properties in the old that are not specified in the new are left as-is.

The state update is asynchronous, so the new state object should not derive values from the current state, which may be out of date when the update occurs. If it is necessary to derive new values from old, an update function should be passed instead:

this.setState((aState, aProps) => ({
  IDNext: aState.IDNext + 1
}));

This function accepts parameters representing the original state and the component props; it then returns new state data, to be merged with the current state. It is invoked during the render phase, and it may be called more than once, so it should not produce side effects.

setState also accepts a callback as an optional second argument, to be invoked after the component is re-rendered.

While component updates are usually triggered by props or state changes, an instance can made to re-render by calling its forceUpdate method. This causes the shouldComponentUpdate lifecycle event to be skipped. It accepts an optional callback argument that is invoked after the forced update.

Component children

When elements are nested within a component’s JSX:

<Sidebar Head="Common problems">
  <ul>
    <li>Uninitialized pointers</li>
    <li>Null pointers</li>
    <li>Dangling pointers</li>
  </ul>
</Sidebar>

they are automatically assigned to the component’s children prop. This allows those children to be embedded within the component’s output:

function Sidebar(aProps) {
  return (
    <section className="Sidebar">
      <header>
        <h3>{aProps.Head}</h3>
      </header>
      {aProps.children}
    </section>
  );
}

It is also possible to pass non-JSX values as children, including functions and other objects. These are then referenced in the component by the children prop, just as a JSX expression would be. The React.Children object provides utility functions like React.Children.map that process these and other child elements.

If the containing component consumes multiple JSX expressions, they can be explicitly assigned to props:

<BoxCompare
  OptA={
    <div>
      <h2>Manual checks</h2>
      <p>Error-prone</p>
      <p>Verbose</p>
    </div>
  }
  OptB={
    <div>
      <h2>Automated checks</h2>
      <p>Resource-intensive</p>
      <p>Less flexible</p>
    </div>
  }
/>

and then embedded in the component output:

function BoxCompare(aProps) {
  return (
    <section className="BoxCompare">
      {aProps.OptA}
      <hr />
      {aProps.OptB}
    </section>
  );
}

As usual, each expression must have a single parent element; otherwise, JSX arrays must be passed.

Render props

The children prop allows the element structure defined by some component to be reused with different children. A render prop provides similar functionality, while also allowing the component to pass data to those children.

The render prop is an ordinary component prop, to which a function has been assigned. It is conventional (but not necessary) to name the prop render:

<Spin render={
  aVal => (<div>Current: {aVal}</div>)
}/>

Note that defining the function in JSX causes a new function instance to be created each time the JSX is evaluated. This could affect performance, and it should not be combined with React.PureComponent, as that class uses reference equality to detect prop changes.

The function accepts whatever arguments the containing component wishes to provide, and returns a JSX expression, to be embedded by the component:

class Spin extends React.Component {
  constructor(aProps) {
    super(aProps);
    this.state = { Val: 0 };

    this.uDec = this.uDec.bind(this);
    this.uInc = this.uInc.bind(this);
  }

  uDec(aEvt) {
    this.setState(aState => ({ Val: aState.Val - 1}));
  }

  uInc(aEvt) {
    this.setState(aState => ({ Val: aState.Val + 1}));
  }

  render() {
    return (
      <div>
        {this.props.render(this.state.Val)}

        <button onClick={this.uDec}>-1</button>
        <button onClick={this.uInc}>+1</button>
      </div>
    );
  }
}

Fragments

Only one top-level element can be returned by a component. To return multiple elements without a container of some sort, wrap them in React.Fragment:

return (
  <React.Fragment>
    <div>LAND C</div>
    <div>LAND X</div>
  </React.Fragment>
);

This can also be written as:

return (
  <>
    <div>LAND C</div>
    <div>LAND X</div>
  </>
);

however, only the full React.Fragment syntax allows key attributes to be assigned to fragments, if the fragments themselves happen to be part of an array. key is the only attribute that can be assigned to a fragment.

Component context

Ordinarily, component configuration data is passed from ancestor elements to descendents via props, but this can be verbose when elements are deeply nested. The React context system allows data to be shared with descendents without forwarding props at each level.

Context data is stored within a context object, created with React.createContext. At render time, ancestor components will assign values to this context, and descendents that subscribe to the context will read from it. React.createContext accepts a single argument that sets the default value, to be read when no value has been assigned by an ancestor in the JSX:

const ContextStat = React.createContext("Red");

The context object defines a Provider component with a value attribute that sets the context value:

<Box />
<ContextStat.Provider value="Green">
  <Box />
  <ContextStat.Provider value="Blue">
    <Box />
  </ContextStat.Provider>
</ContextStat.Provider>

This value is available to all components contained by the Provider, regardless of depth. When providers are nested, each value takes precedence over the ones above it. Subscribing components are updated when a value changes, even if their shouldComponentUpdate methods return false.

By default, in the React DevTools Components page, all provider components are listed as Context.Provider, regardless of the context object that defines them. The displayName property within the context object can be used to replace Context with a distinct name:

ContextStat.displayName = "ContextStat";

A class component subscribes to the context by assigning the context object to its class-static contextType variable. At render time, it reads the current value from its own context property:

class Box extends React.Component {
  static contextType = ContextStat;

  render() {
    return (
      <div className={`Box ${this.context}`}>
        PEND
      </div>
    );
  }
}

In the past, a function component subscribed to the context by embedding the Consumer component defined within the context object. This component interprets its child as a render prop, which itself receives the current context value as an argument, and returns the content to be displayed within the Consumer:

function Box(aProps) {
  return (
    <ContextStat.Consumer>
      {aVal => (
        <div className={`Box ${aVal}`}>
          PEND
        </div>
      )}
    </ContextStat.Consumer>
  );
}

Now, function components can read context values by calling the useContext hook. This allows context data to be used without passing a render prop.

By embedding multiple Consumer components, a function component can subscribe to multiple contexts. Class components can subscribe to at most one, so the context must store an object if multiple values are needed:

const ContextStat = React.createContext({ Sty: "Red", Text: "PEND" });

class Box extends React.Component {
  static contextType = ContextStat;

  render() {
    return (
      <div className={`Box ${this.context.Sty}`}>
        {this.context.Text}
      </div>
    );
  }
}

However, React compares context values by reference when checking for changes. If provider values are assigned in JSX with object literals:

<ContextStat.Provider value={{ Sty: "Green", Text: "READY" }}>

new value objects will be created every time the JSX is evaluated, the value comparison will always fail, and unnecessary DOM updates will result. To avoid this, value objects should be stored in the component state, and referenced from the Provider element:

class App extends React.Component {
  constructor(aProps) {
    super(aProps);

    this.state = {
      StatReady: { Sty: "Green", Text: "READY" },
      StatAct: { Sty: "Blue", Text: "ACT" }
    };
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <Box />
          <ContextStat.Provider value={this.state.StatReady}>
            <Box />
            <Box />
            <ContextStat.Provider value={this.state.StatAct}>
              <Box />
            </ContextStat.Provider>
          </ContextStat.Provider>
        </header>
      </div>
    );
  }
}

Element refs

Ordinarily, page content is modified by changing component props or state, causing them to be re-rendered. The React element tree then produces DOM elements, which may be generated conditionally, or configured with conditional attributes or content. However, parent components cannot call child component methods directly, because component instances are created and managed by React. Nor can parents access DOM element instances.

A React ref provides direct access to a React component or DOM element instance. Ref objects are created with React.createRef. This function accept no arguments, and is often called in a component constructor:

class InName extends React.Component {
  constructor(aProps) {
    super(aProps);

    this.RefIn = React.createRef();
    this.uFocus_In = this.uFocus_In.bind(this);
  }
  ...

At this point, the object references nothing. It is associated with a component or DOM element by assigning it to the target’s ref attribute during rendering:

render() {
  return <input name="Name" ref={this.RefIn} />;
}

The component or DOM element instance is then accessible through the current property in the ref object:

uFocus_In() {
  if (this.RefIn.current) this.RefIn.current.focus();
}

Until recently, function components were stateless, so they could not define refs. They can define them now with ref hooks.

Callback refs

A reference to a component or DOM element can also be obtained by assigning a callback function to the ref attribute:

<input name="Name" ref={this.uSet_RefIn} />

The callback is invoked when the component is mounted or unmounted. It accepts a single parameter that gives the new element reference, or null, as appropriate:

uSet_RefIn(aRef) {
  this.RefIn = aRef;
}

If the callback is a class method, it should be bound to this, like other event handlers:

constructor(aProps) {
  super(aProps);

  this.uSet_RefIn = this.uSet_RefIn.bind(this);
  this.uFocus_In = this.uFocus_In.bind(this);
}

The reference itself is passed to the callback, so there is no current property:

uFocus_In() {
  if (this.RefIn) this.RefIn.focus();
}

Forwarded refs

A component cannot assign a ref attribute to a component or DOM element unless the target is defined in the referencing component’s render function. The target can forward a ref it has received, however, allowing the parent to reference components or elements it does not render directly.

React.forwardRef creates a special function component that forwards a ref to one of its own children. It accepts a callback that itself resembles a function component; the callback accepts props and ref arguments, and returns component content:

const InDock = React.forwardRef((aProps, aRef) => (
  <input name={"InDock" + aProps.ID} ref={aRef} />
));

React.forwardRef then returns the ref-forwarding component. Refs are assigned to the new component’s ref attribute as usual:

class BoxDoc extends React.Component {
  constructor(aProps) {
    super(aProps);

    this.RefIn = React.createRef();
    this.uReady = this.uReady.bind(this);
  }

  uReady() {
    this.RefIn.current.focus();
    ...
  }

  render(aProps) {
    return (
      <div>
        <InDock ref={this.RefIn} />
        ...
      </div>
    );
  }
}

Class components cannot be passed to React.forwardRef. They can be wrapped in a function component that forwards the reference through a prop, however. The forwarding prop cannot be named ref, as that attribute is handled specially by React:

const InDock = React.forwardRef((aProps, aRef) => (
  <InDockBase {...aProps} RefForw={aRef} />
));

The forwarding prop can then be assigned to ref in the underlying class component:

class InDockBase extends React.Component {
  render() {
    return (
      <input name={"InDock" + this.props.ID} ref={this.props.RefForw} />
    )
  }
}

Lifecycle methods

Various lifecycle methods are invoked on class components as they are added to the page, updated, and later removed. Implementing these methods allows the component to perform special handling during these events.

Component mounting

A component is said to be mounted after it is first added to the page. The following methods are invoked during and after mounting:

  • The component constructor;
  • The static getDerivedStateFromProps method, which allows components to modify their state in response to props changes;
  • The render method;
  • The componentDidMount method.

Component updates

The following methods are invoked during the update phase, in response to props or state changes:

  • The static getDerivedStateFromProps method;
  • The shouldComponentUpdate method, which allows a component to bypass an update if the props or state change that triggered it does not affect its output;
  • The render method;
  • The getSnapshotBeforeUpdate method, which is invoked before changes are reflected in the DOM, allowing components to collect information about the previous DOM state;
  • The componentDidUpdate method.

Component unmounting

A component is said to be unmounted after it is removed from the page. One method is invoked when unmounting:

  • The componentWillUnmount method.

Higher-order components

A higher-order component or HOC is a function that receives a component as an argument and returns a new component:

// Returns a new component that passes the result of function
// 'afSrcData' to component 'Child' through the 'Data' prop.
// Call method 'fUpd' in the new component to update the data:
function Forw_Data(Child, auSrcData) {
  return class extends React.Component {
    constructor(aProps) {
      super(aProps);
      this.state = { Data: auSrcData() };
    }

    uUpd() {
      this.setState(aState => ({ Data: auSrcData() }));
    }

    render() {
      return <Child Data={this.state.Data} {...this.props} />;
    }
  };
}

This can be used to compose functionality. The child component is passed to the HOC, along with any other arguments that might be required. The HOC can share state data with its child by assigning a prop. Other props are forwarded to the child with the props spread syntax.

The HOC result is stored in a variable:

function BoxLot(aProps) {
  return <div>...</div>
}

function uDataLot() {
  return { ... }
}

const Lot = Forw_Data(BoxLot, uDataLot);

and then used like any other component:

<div>
  <Lot />
  ...

If the HOC were invoked in another component’s render method, a new class would be created with each update, and performance would suffer.

It is particularly easy to define an HOC if the containing component already exists, and if it offers a render prop:

class BridgeData extends React.Component {
  constructor(aProps) {
    super(aProps);
    this.state = { Data: aProps.uSrcData() };
  }

  uUpd() {
    this.setState(aState => ({ Data: this.props.uSrcData() }));
  }

  render() {
    return this.props.render(this.state.Data);
  }
}

The HOC simply returns a new function component that embeds the child within the forwarded render function:

function Forw_Data(Child, auSrcData) {
  return aProps => (
    <BridgeData uSrcData={auSrcData} render={
      aData => (<Child Data={aData} {...aProps} />)
    } />
  );
}

Whereas the containing component in the first example passes data to the child by embedding it as a prop within its JSX, the container in the second passes it as an argument to the supplied render prop function, which embeds it within its own JSX.

Note that ref assignments look like props, but they are handled specially by React. If an ordinary ref is assigned to an HOC, it will come to reference the HOC itself, not the child component. If necessary, the HOC can use React.forwardRef to forward the ref to its child.

Forms

Controlled components

Once displayed in the page, most elements change their appearance and behavior only in response to DOM operations. In React, a component’s props or state are updated, causing the component to be re-rendered, and the DOM to be updated.

Form inputs respond to DOM operations, but they also respond directly to user input, even though their props and state have not changed. To make their state management consistent with other React elements, form inputs can be implemented as controlled components, which are inputs that are explicitly backed by React state data. In this context, the word component refers to a DOM element, rather than a React class or function component.

Multiple controlled components can be implemented by a single form component. Within render, each form element draws its value from the form component state. Most element content is set with the value attribute; this includes elements like select and textarea that specify values differently in HTML. Assigning an array to value selects multiple options, in controls that support such. Checkbox values are set with checked:

class FormAddLot extends React.Component {
  constructor(aProps) {
    super(aProps);

    this.state = {
      IDLot: "000",
      CkBypass: false
    };

    this.uHandChg = this.uHandChg.bind(this);
    this.uHandSubmit = this.uHandSubmit.bind(this);
  }

  uHandChg(aEvt) {
    const oEl = aEvt.target;
    const oVal = (oEl.type === "checkbox") ? oEl.checked : oEl.value;
    const oProp = { [aEvt.target.name]: oVal };
    this.setState(oProp);
  }

  uHandSubmit(aEvt) {
    aEvt.preventDefault();
    ...
  }

  render() {
    return (
      <form onSubmit={this.uHandSubmit}>
        <div><label>Lot ID
          <input name="IDLot" value={this.state.IDLot}
            onChange={this.uHandChg} />
        </label></div>

        <div><label>Mode
          <select name="Mode" value={this.state.Mode}
            onChange={this.uHandChg}>
            <option value="Ready">Ready</option>
            <option value="Stand">Stand</option>
          </select>
        </label></div>

        <div><label>Bypass
          <input name="CkBypass" type="checkbox"
            checked={this.state.CkBypass}
            onChange={this.uHandChg} />
        </label></div>

        <input type="submit" value="Add" />
      </form>
    );
  }
}

This approach is called one-way data binding.

An onChange handler is assigned to each form control, and this handler updates the component state to match the user-entered value. The update causes the control to be re-rendered with a value that matches what was entered. If the onChange handler is omitted, the component’s state will go unchanged, and the user’s input will be overwritten with the default value, making the control effectively read-only. Controls set to null or undefined values in render are always editable, however.

In HTML, an input is associated with a label by defining it as a child element, or by referencing it with the for label attribute. In JSX, for is replaced by htmlFor.

Uncontrolled components

Uncontrolled components are not backed by React state data; instead, React refs are used to reference DOM elements within the form, and the DOM API is used to read their values:

class FormCatAdd extends React.Component {
  constructor(aProps) {
    super(aProps);

    this.RefInCd = React.createRef();
    this.RefInName = React.createRef();
    this.uHand_Submit = this.uHand_Submit.bind(this);
  }

  uHand_Submit(aEvt) {
    aEvt.preventDefault();

    Add_Cat({
      Cd: this.RefInCd.current.value,
      Name: this.RefInName.current.value
    });
  }

  render() {
    return (
      <form onSubmit={this.uHand_Submit}>
        <div><label> Code:
          <input type="text" defaultValue="A0" ref={this.RefInCd} />
        </label></div>
        <div><label> Name:
          <input type="text" ref={this.RefInName} />
        </label></div>
        <input type="submit" value="Add" />
      </form>
    );
  }
}

In React, the defaultValue attribute can be used to display a default value when the form appears, without overwriting the user’s input, as value does. Checkbox and radio button defaults can be set with defaultChecked.

File inputs do not allow their values to be set with the DOM API, so they must be implemented as uncontrolled components:

<input name="NameFile" type="file" />

Page output

React.createElement

All React output is ultimately produced by React.createElement. JSX in particular is translated at compile time to nested invocations of this method:

React.createElement(type, [props], [...children])
Returns an immutable ReactElement instance. The content is defined by type, which references a React component, or a string that contains an HTML tag name. props can be set to an object that specifies the props for the new element, or null or undefined if no props are needed. children can be set to one or more ReactElement instances, or a single array of such. These become children of the new element.

When children references an array, each child must define a unique key value:

const oElA = React.createElement("div", { key: "A" }, "Area A");
const oElB = React.createElement("div", { key: "B" }, "Area B");
return React.createElement(React.Fragment, {}, [oElA, oElB]);

This is not necessary when children are passed as separate arguments:

const oElA = React.createElement("div", {}, "Area A");
const oElB = React.createElement("div", {}, "Area B");
return React.createElement(React.Fragment, {}, oElA, oElB);

ReactDOM.render

React output is typically embedded in the page with ReactDOM.render:

ReactDOM.render(elem, contain, [call])
Causes ReactElement instance elem to be added to DOM element contain. elem and its children replace the content of contain. If function call is provided, it will be invoked after contain is updated.

Though they can define any number of separate container elements, pages often have a single root element:

<div id="Root"></div>

that contains the entire app:

const oElApp = (
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

ReactDOM.render(
  oElApp,
  document.getElementById("Root")
);

React maintains an abstract representation of the container content called the virtual DOM or VDOM. During the render phase, component render functions are invoked to produce a new virtual DOM tree, which React compares against the existing virtual DOM. The following functions may be called one or more times during the render phase, so they should not produce side effects:

  • Component constructors;
  • getDerivedStateFromProps;
  • State update functions passed to setState;
  • shouldComponentUpdate;
  • Component render functions.

During the commit phase, React updates the browser DOM to reflect any changes it detected, then it stores the new virtual DOM. The process as a whole is called reconciliation.

By default, a component is re-rendered if its props or state change. The component’s children are rendered as well. To improve performance, class components can override the shouldComponentUpdate method and return false if neither they nor their children should be updated in response to the change. Components can also subclass React.PureComponent, in place of React.Component. This class compares props and state data to determine whether content has changed. It compares only top-level values in the props and state objects, leaving arrays and other object values to be compared by reference.

React output can be removed from the page by calling ReactDOM.unmountComponentAtNode, which accepts a single argument that gives the DOM element that contains the output.

Portals

Ordinarily, a component’s output is written to its position in the element hierarchy. Any elements it generates become children of the component’s parent, and siblings of the component’s siblings. A portal can be used to direct output to a DOM element other than the component’s parent.

To do this, the component invokes ReactDOM.createPortal within its render function, and returns the resulting portal instance. This method is invoked much like ReactDOM.render:

ReactDOM.createPortal(elem, contain)
Creates and returns a portal object that causes ReactElement elem to be rendered into DOM element contain, rather than the parent of the invoking component. elem and its children replace the content of contain.

By invoking ReactDOM.createPortal conditionally, a component can send its output to a portal, or to the component’s parent, as usual:

const ElDlg = document.getElementById("Dlg");

function SecMsg(aProps) {
  const oOut = (
    <section>
      <h3>{aProps.Head}</h3>
      <div>
        {aProps.Msg}
      </div>
    </section>
  );

  if (aProps.CkDlg) return ReactDOM.createPortal(oOut, ElDlg);
  return oOut;
}

Many DOM events bubble up through the element hierarchy until stopPropagation is invoked on the event. React propagates its own SyntheticEvent instances through the React element tree, and these events continue to move through the hierarchy that contains the portal-using control, even though the control’s output has been redirected to a different hierarchy within the DOM.

Error boundaries

Ordinarily, when a component throws an exception from its constructor, its render method, or a lifecycle method, the entire component tree is removed from the page. Error boundaries are special components that catch these exceptions when they are thrown from contained components. This allows errors to be logged, and fallback content to be displayed.

A class component will act as an error boundary if it defines one or both of getDerivedStateFromError and componentDidCatch. Function components cannot serve as boundaries.

getDerivedStateFromError is a class-static method that is called by React when a contained component throws. It receives the exception as a parameter, and returns an object that React uses to update the state. Often, this state object sets a property that the render method uses to detect error conditions and display fallback content:

static getDerivedStateFromError(aErr) {
  return { CkErr: true };
}

componentDidCatch is a component class method that is called by React after getDerivedStateFromError. It receives the exception as an argument, plus an object containing a componentStack property that stores a stack trace:

componentDidCatch(aErr, aInfoErr) {
  Log.Add(aErr, aInfoErr);
}

Note that development builds display exception text and stack traces in the page even when those exceptions are caught by error boundaries. To see the page as it would be rendered by a production build, press Esc.

Error boundaries do not catch exceptions thrown from DOM event handlers or asynchronous functions. Event handler exceptions do not cause the component tree to be deleted, however.

Hooks

Function components produce no component instances, so they are traditionally unable to maintain component state, or use stateful features like refs. React 16.8 introduced hooks, which are special functions that add these abilities to function components.

Several rules apply to hook usage. CRA installs an ESLint plugin eslint-plugin-react-hooks that checks some of these at compile time:

  • Hooks are usable only within function components, or within custom hook functions. They cannot be used in class components;
  • Hooks that are called once must be called every time the component is rendered, and in the same order. For this reason, they may not be called conditionally, or from event handlers, nor may the containing function place a conditional early return before any hook. eslint-plugin-react-hooks also prevents hooks from being called within loops, even when the iteration count is fixed. It is also recommended that hooks not be called within nested functions.

When a hook is invoked from a function component, it creates or modifies state data that is specific to the component instance. When the component instance is rendered again, the same hook comes to reference the same data.

State hooks

State hooks are created with the useState function within the react package. They allow function components to manage state, much the way class components do with setState:

import React, { useState } from "react";

Each useState call defines a single state variable, which can store a primitive or an object:

function Spin(aProps) {
  const [oVal, ouSet_Val] = useState(aProps.ValDef | 0);

  function ouInc(aEvt) { ouSet_Val(aVal => (aVal + 1)); }
  function ouDec(aEvt) { ouSet_Val(aVal => (aVal - 1)); }

  return (
    <div>
      <div>{oVal}</div>
      <button onClick={ouDec}>-1</button>
      <button onClick={ouInc}>+1</button>
    </div>
  );
}

useState accepts a starting value for the variable, or a function that returns such a value. It returns an array containing the current value, plus a function that can be used to update the value.

The update function does not merge state objects the way setState does; it completely replaces them. It can accept a new value, or a callback that accepts the current value and returns the new one. This should be used if the new value derives from the original.

Calling useState more than once produces multiple state variables; React uses the order of these calls to link each with its particular variable. It is recommended that values or objects that vary independently be managed with separate useState variables.

When the component is selected in the React DevTools Components tab, its hooks and their associated data are listed in the hooks section within the component properties.

Reducer hooks

Reducer hooks can be used to manage state in components with complex state transitions.

A reducer is a pure function that accepts an object representing the current state, plus a second action argument that signals a state transition. The reducer uses these to create and return an object representing the next state.

useReducer can be called with two or three arguments. The first argument is always a reducer. When two arguments are passed, the second argument is an object that defines the initial state of the component. When three are passed, the third is a function that accepts the second useReducer argument and returns the initial state.

useReducer returns an array containing the next state object, plus a dispatcher. This function accepts an action argument and forwards it to the reducer, thus triggering the next state transition:

import React, { useReducer } from "react";

function uStNextSpin(aSt, aAct) {
  switch (aAct.Type) {
    case "DEC":
      return { Val: aSt.Val - aAct.Qty }
    case "INC":
      return { Val: aSt.Val + aAct.Qty }
    default:
      throw Error("uStNextSpin: Invalid action type");
  }
}

function Spin(aProps) {
  const oStInit = { Val: aProps.ValDef | 0 };
  const [oSt, ouDispatch] = useReducer(uStNextSpin, oStInit);

  function ouDec1(aEvt) { ouDispatch({ Type: "DEC", Qty: 1 }); }
  function ouDec10(aEvt) { ouDispatch({ Type: "DEC", Qty: 10 }); }

  function ouInc1(aEvt) { ouDispatch({ Type: "INC", Qty: 1 }); }
  function ouInc10(aEvt) { ouDispatch({ Type: "INC", Qty: 10 }); }

  return (
    <div>
      <div>{oSt.Val}</div>
      <button onClick={ouDec10}>-10</button>
      <button onClick={ouDec1}>-1</button>
      <button onClick={ouInc1}>+1</button>
      <button onClick={ouInc10}>+10</button>
    </div>
  );
}

useReducer returns the same dispatcher instance each time, allowing the dispatcher to be assigned as a prop without producing unnecessary updates.

Effect hooks

Like all render functions, function components are prohibited from producing side effects, at least directly. These effects include DOM changes, network requests, and even logging.

Effect hooks provide a way to run side-effect-producing code in function components, serving much as componentDidMount, componentDidUpdate, and componentWillUnmount do in class components.

useEffect accepts an effect function with no parameters. React will call this function some time after the component has been rendered and the browser repainted, so side effects are allowed:

import React, { useState, useEffect } from "react";

function StatPress(aProps) {
  const [oData, ouSet_Data] = useState(null);

  function uSub_Data() {
    function ouUpd_Data(aData) { ouSet_Data(aData); }

    PubDataStat.Add_Sub(CdStatPress, ouUpd_Data);
    return () => PubDataStat.Rem_Sub(CdStatPress, ouUpd_Data);
  }
  useEffect(uSub_Data, []);

  if (!oData) return "PEND";

  return (
    <section>
      <h2>Pressure</h2>
      <div>Current: {oData.Curr}</div>
      ...
  );
}

The effect function can also return a zero-parameter cleanup function; if it does, React will call this function before the effect function is called again, and also before the component is unmounted.

By default, React calls the effect after every render, and the cleanup before every effect, after the first. However, useEffect accepts an optional array of state variables as its second argument. If provided, React stores these values and compares them by reference after each render; neither the cleanup function nor the effect are invoked unless one or more of the values change. If an empty array is passed, both functions are run exactly once: the effect after the first render, and the cleanup before the component unmounts.

Like useState, useEffect can be called more than once in a given component.

Layout effect hooks

Ordinary effect hooks run after the browser has painted the changed component. Sometimes it is necessary to update the DOM manually after rendering, and it is preferable to do this before painting. This can be done with useLayoutEffect, which is identical to useEffect, except that its effect and cleanup functions run before the browser is allowed to paint.

Context hooks

In the past, function components used context values by assigning a render prop to the context object’s Consumer component. Context hooks provide a simpler way to read those values.

The context object is created with React.createContext, as before, and its value is assigned the same way, by embedding the object’s Provider component and setting the associated value prop. However, the function component can now read the value simply by passing the context object to useContext:

function Box(aProps) {
  const oVal = useContext(ContextStat);
  return <div className={`Box ${oVal}`}>PEND</div>
}

Ref hooks

Class components use React refs to reference component or DOM element instances that they have rendered. Traditionally, this has not been possible for function components, but ref hooks now allow it to be done. In fact, these refs are more general than the element refs produced by React.createRef; they can be used to persist any sort of data, for use by event handlers, or by future iterations of the calling function.

Hook ref objects are created with useRef. Unlike React.createRef, this function accepts a single argument that determines the starting value of the ref’s current property. Much like useState, the same object is returned every time a particular useRef call is executed.

The current property is made to reference a component or DOM element instance by assigning it to the ref attribute in the target. As usual, this value is not set until the first time the component renders:

function PanLog(aProps) {
  const oRefBtn = useRef(null);

  function uReady() {
    oRefBtn.current.focus();
    ...
  }
  useEffect(uReady, []);

  return (
    <div>
      <button ref={oRefBtn}>Reset</button>
      ...
  );
}

The current property can also be set manually, to any value, as can any other property in the ref object. The result is something like a static local variable in another language. Unlike component props or state, changing such a value does not cause the component to be re-rendered.

Customizing element ref output

By default, when a ref is assigned to an element’s ref attribute, its current property is made to reference the component or DOM element instance. useImperativeHandle can be used to assign a different value to current.

The target component must be implemented as a React.forwardRef callback, with props and ref arguments. If it needs to reference one of its own children, it creates its own ref and assigns that as usual; it does not use the ref it received as a parameter, as that will be read by the target’s parent. The component passes the ref it received to useImperativeHandle, along with a callback that accepts no arguments, and returns the value or object that should be assigned to current:

function PanPowBase(aProps, aRef) {
  const oRefBtn = useRef();
  function ouReady() {
    ...
    oRefBtn.current.focus();
  }

  useImperativeHandle(aRef, () => ({ Ready: ouReady }));

  return (
    <>
      <div>
        PanPow
        <button ref={oRefBtn} onClick={...}>Run</button>
      </div>
      <div>
        {oVal}
      </div>
    </>
  );
}

As always when forwarding refs, React.forwardRef is used to create the finished component:

const PanPow = React.forwardRef(PanPowBase);

The parent assigns a ref to the target as usual, and obtains the target’s data from the ref object’s current property:

function PanMain(aProps) {
  const oRefPanPow = useRef(null);
  function ouReady() { oRefPanPow.current.uReady(); }

  return (
    <div>
      <PanPow ref={oRefPanPow} />
      <button onClick={oReady}>Ready</button>
    </div>
  );
}

Memoization hooks

Memoization refers to the caching and reuse of output values by some function. Memoization hooks provide an easy way to memoize slow operations within function components.

useMemo accepts the target function, plus an array of state variables. It does not pass arguments when it invokes the target, so an arrow function may be used to capture and forward props or state variables:

function PanCool(aProps) {
  const [oFreqCut, ouSet_FreqCut] = useState(800);
  const [oWth, ouSet_Wth] = useState(1);

  const oCoeffs = useMemo(
    () => CoeffsFilt(oFreqCut, oWth),
    [oFreqCut, oWth]
  );
  ...

Much like useEffect, values in the state variable array are stored and compared each time a given useMemo hook is invoked; the target function is evaluated the first time the hook runs, and again if any state value changes. useMemo caches only the most recent target result. The array elements typically match the state variables that were captured by the target function, and eslint-plugin-react-hooks warns if any of these are omitted in the array. If the array is empty, the target will be invoked only once. If the array argument is omitted, the target will be invoked every time, bypassing the memoization entirely.

Callback memoization

Sometimes it is desireable to pass a function to a child element through one of its props, for use as an event handler. Ordinarily, if this handler is defined in a function component, a new function instance will be created during each render, which could cause the child component to re-render unnecessarily.

This problem can be avoided with useCallback, a hook that memoizes function instances, rather than function results. Like useMemo, it accepts a target function and an array of state variables. Rather than invoking the target, it returns a new function that wraps the target, and it returns the same wrapper instance until one or more of the state values change.

The same could easily be done with useMemo. Given function target and array vars:

useCallback(target, vars)

is equivalent to:

useMemo(() => target, vars)

Custom hooks

A custom hook is a function that calls other hooks, allowing related state management functionality to be collected and reused in different function components. The name of the custom hook must begin with use, but the function itself can have any signature. This allows the hook to gather any sort of data, perform stateful work, and then return any sort of result, for use during the component render.

The rules that govern built-in hooks also apply to custom hooks. In particular, custom hooks that are called once must be called every time, and in the same order.

Debug string hooks

When a component is selected in the React DevTools Components tab, its hooks and their associated data are listed in the hooks section within the component properties. Custom hooks are also listed there. If a string is passed to useDebugValue, that value will be displayed in a label next to the custom hook name.

Sources

React documentation
Add React to a Website, Building Your Own Hooks, Context, Create a New React App, DOM Elements, Error Boundaries, Forms, Forwarding Refs Higher-Order Components, Hooks at a Glance, Hooks API Reference, Hooks FAQ, Introducing Hooks, JSX In Depth, Portals, React Top-Level API, React.Component, ReactDOM, Reconciliation, Refs and the DOM, Rules of Hooks, Strict Mode, SyntheticEvent, Typechecking With PropTypes, Uncontrolled Components, Using the Effect Hook, Using the State Hook, Virtual DOM and Internals
Retrieved December 2021

Create React App documentation
Adding Images, Fonts, and Files, Adding a Stylesheet, Advanced Configuration, Code Splitting, Folder Structure, Using the Public Folder
Retrieved December 2021

Create React App GitHub page
Retrieved December 2021

Stack Overflow
How to use React.forwardRef in a class based component?, What does the callback in forceUpdate do?, What is JavaScript's CompositionEvent?
Retrieved December 2021

React (Virtual) DOM Terminology
Sebastian Markbåge
Retrieved December 2021

web.dev
Add a web app manifest
Retrieved January 2022

Webpack documentation
Asset Management
Retrieved January 2022