React.js

Components and props

Components are like functions: they accept inputs called "props" (short for "properties") and return React elements, which describe what should appear onscreen.

Two equivalent ways to define a component follow. Note that the only things needed for us to officially call it a component are the object input "props" and that they return a React element.

// A component
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

// A component
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

JSX

React recommends an extended Javascript syntax called JSX. A line of JSX can look like this:

const element = <h1>Hello, world!</h1>;

Instead of separating technologies by putting markup and logic in separate files, React separates concerns with loosely coupled units called “components” that contain both.

Babel compiles JSX down to React.createElement() calls.

These two examples are identical:

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

More: reactjs.org/docs/jsx-in-depth.html

TypeScript

Either use .tsx and enable jsx in your TypeScript compiler, or, stay with .jsx and write according to Flow markup instead of TypeScript.

Flow needs Babel to lint

React+Flow needs Babel if you want linting above and beyond what linting Flow itself provides.

ESLint's default parser and core rules only support the latest final ECMAScript standard and do not support experimental (such as new features) and non-standard (such as Flow or TypeScript types) syntax provided by Babel. babel-eslint is a parser that allows ESLint to run on source code that is transformed by Babel.

Note: You only need to use babel-eslint if you are using Babel to transform your code. If this is not the case, please use the relevant parser for your chosen flavor of ECMAScript (note that the default parser supports all non-experimental syntax as well as JSX).

Note that you need Babel anyway if using JSX syntax.

Fix Flow problems

In your Dockerfile:

# Fix Flow on Alpine: https://github.com/facebook/flow/issues/7509
CMD apk add gcompat

# So you can run `flow` instead of `./node_modules/.bin/flow`
ENV PATH /app/node_modules/.bin:$PATH

Imports

Some random import lines:

import React from 'react'
import logo from './logo.svg';
import './App.css';

The first line just imports the react library, which is essential to run a React app even if it doesn't appear as if we directly call any React method in the code(!); Babel expands the JSX pseudo-HTML snippets into React.createElement calls.

Importing './App.css' also may not appear to do anything, but it tells the bundler, webpack, to include it. And that is how you get away without having any sort of index.html!

(And what starts webpack in the first place? It's done from react-scripts start.)

Style guide

I found style guides like airbnb.io/javascript/react/ surprisingly enlightening as to how people actually use React in the wild. Such rules as "one React component per file" tell me something about how many stateful components are actually expected, for example.

Front-end and back-end

React.js is a front-end thing only. So you would not use npx create-react-app for the backend.

Client-side routing

Here is a reason to make a SPA (single-page app) with <Routes> instead of a multi-page app:

In traditional websites, the browser requests a document from a web server, downloads and evaluates CSS and JavaScript assets, and renders the HTML sent from the server. When the user clicks a link, it starts the process all over again for a new page.

Client side routing allows your app to update the URL from a link click without making another request for another document from the server. Instead, your app can immediately render some new UI and make data requests with fetch to update the page with new information.

This enables faster user experiences because the browser doesn't need to request an entirely new document or re-evaluate CSS and JavaScript assets for the next page. It also enables more dynamic user experiences with things like animation.

Client side routing is enabled by creating a Router and linking/submitting to pages with Link and <Form>:

Loading assets

NOTE: You do not need a webpack.config.js, React ships a config! (And if you want to edit webpack config, use CRACO.)

In React, they recommend you put assets in src/, the same directory you have your component code, and import them with a JS import statement. (create-react-app.dev/docs/adding-images-fonts-and-files/)

However, files can be imported as "raw", "file" or "url", and it auto-chooses a loader by looking at the filename extension, but that won't always be what you want.

As of [2023-03-14 Tue] they're working on a way to specify loader type (github.com/facebook/create-react-app/issues/3722). In the meantime, put your asset in the public/ folder. (create-react-app.dev/docs/using-the-public-folder/)

GOTCHA: Your assets must be world-readable, i.e. chmod 644, not chmod 600! If it's 600, fetching an asset may get you a "403 Forbidden" response.

To fetch an asset located at public/text.md, write:

fetch(process.env.PUBLIC_URL + 'text.md')

and rebuild the app.

Cookies

GOTCHA: it seems you cannot pass react-use-cookie hooks instantiated in a parent component to its children. Instead, the children must make new calls to useCookie themselves. Think of it as if all components are always subscribed to a React Context for all cookies; use the cookie rather than passed props.

What links here

  • Web-dev
Created (18 months ago)