tags : Web Development

These are notes taken while reading the react docs

Basic Theory

Elements

  • Elements are the smallest building blocks of React apps.
  • Elements are what components are “made of”
  • Unlike browser DOM elements, React elements are plain objects, and are cheap to create.
    • React DOM takes care of updating the DOM to match the React elements.
  • React elements are immutable. Once you create an element, you can’t change its children or attributes.
  • Can represent DOM tags, also can represent user-defined components.

React DOM

  • React DOM compares the element and its children to the previous one.
    • Only applies the DOM updates necessary to bring the DOM to the desired state.
  • JSX.Element -> Return value of React.createElement
  • React.ReactNode -> Return value of a component

Components

  • Components are like JavaScript functions.
    • They accept arbitrary inputs (called “props”)
    • Return React elements describing what should appear on the screen.
  • React treats components starting with lowercase letters as DOM tags.
    • So always start component names with a capital letter.
  • All React components must act like pure functions with respect to their props.

Controlled components

  • An input form element whose value is controlled by React in this way is called a “controlled component”.

State

  • State is similar to props, but it is private and fully controlled by the component.
  • this.props and this.state may be updated asynchronously
    • You should not rely on their values for calculating the next state.
// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((state, props) => ({
  counter: state.counter + props.increment
}));
  • State is often called local or encapsulated.
    • It is not accessible to any component other than the one that owns and sets it
    • Neither parent nor child components can know if a certain component is stateful or stateless
    • A component may choose to pass its state down as props to its child components, but wouldn’t know whether it came from the parent’s state, props, or was handtyped.

Events

  • Here, e is a synthetic event.
    • A cross-browser wrapper around the browser’s native event.
    • It has the same interface as the browser’s native event, including stopPropagation() and preventDefault()
    • Except the events work identically across all browsers.
  • You cannot return false to prevent default behavior in React. You must call preventDefault explicitly.
  • Generally, if you refer to a method without () after it, such as onClick={this.handleClick}, you should bind that method.
// with class fields syntax
class LoggingButton extends React.Component {
  // This syntax ensures `this` is bound within handleClick.
  handleClick = () => { console.log('this is:', this);  };
  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

// without class fields syntax
class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }
  render() {
    // This syntax ensures `this` is bound within handleClick
    return (<button onClick={() => this.handleClick()}> Click me  </button>
    );
  }
}

// passing args
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>

Rendering

  • You might want a component to hide itself even though it was rendered by another component. To do this return null instead of its render output.
  • If you choose not to assign an explicit key to list items then React will default to using indexes as keys. But prefer if list data has its own keys.

Composition

  • Some components don’t know their children ahead of time.
    • Use the special children prop to pass children elements directly into their output.
const FancyBorder = (props) =>
      <div className={'FancyBorder FancyBorder-' + props.color}>
        {props.children}
      </div>

Advanced topics

Accessibility

no notes on a11y now

Code splitting

Basically splitting your bundles into smaller size for faster load times.

import()

// before
import { add } from './math';
console.log(add(16, 26));
// after
import("./math").then(math => {
  console.log(math.add(16, 26));
});

React.lazy

  • React.lazy currently only supports default exports.
// requires the use of suspense
import React, { Suspense } from 'react';
import Tabs from './Tabs';
import Glimmer from './Glimmer';
 
const Comments = React.lazy(() => import('./Comments'));
const Photos = React.lazy(() => import('./Photos'));
 
function MyComponent() {
  const [tab, setTab] = React.useState('photos');
 
  function handleTabSelect(tab) {
  startTransition(() => {
    setTab(tab);
  });
 
  return (
    <div>
      <Tabs onTabSelect={handleTabSelect} />
      <Suspense fallback={<Glimmer />}>
        {tab === 'photos' ? <Photos /> : <Comments />}
      </Suspense>
    </div>
  );
}

Additionally Error boundaries can be used to show if any errors while loading.

Context

  • Context provides a way to pass data through the component tree without having to pass props down manually at every level.
  • Designed to share data that can be considered “global” for a tree of React components, such as the current authenticated user, theme, or preferred language.
  • Apply it sparingly because it makes component reuse more difficult.

React.createContext

  • The defaultValue argument is only used when a component does not have a matching Provider above it in the tree.
  • passing undefined as a Provider value does not cause consuming components to use defaultValue.

Context.Provider

  • All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes.
  • The propagation from Provider to its descendant consumers (including .contextType and useContext) is not subject to the shouldComponentUpdate method

Class.contextType

  • Using this property lets you consume the nearest current value of that Context type using this.context
  • You can only subscribe to a single context using this API.

Context.Consumer

  • The value argument passed to the function will be equal to the value prop of the closest Provider for this context above in the tree.
  • Using this we can subscribe to multiple contexts
    <MyContext.Consumer>
      {value => /* render something based on the context value */}
    </MyContext.Consumer>

Error Boundaries

A JavaScript error in a part of the UI shouldn’t break the whole app. To solve this problem for React users, React 16 introduces a new concept of an error boundary.

  • Use static getDerivedStateFromError() to render a fallback UI after an error has been thrown.
  • Use componentDidCatch() to log error information.
  • Error boundaries work like a JavaScript catch {} block, but for components.
  • In practice, most of the time you’ll want to declare an error boundary component once and use it throughout your application.
  • For example, Facebook Messenger wraps content of the sidebar, the info panel, the conversation log, and the message input into separate error boundaries. If some component in one of these UI areas crashes, the rest of them remain interactive.
  • Error boundaries do not catch errors inside event handlers.

Refs

Refs provide a way to access DOM nodes or React elements created in the render method. The child to be modified could be:

  • An instance of a React component
  • It could be a DOM element.

Avoid using refs for anything that can be done declarative. Some usecases:

  • Managing focus, text selection, or media playback.
  • Triggering imperative animations.
  • Integrating with third-party DOM libraries.
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    // create a ref
    this.myRef = React.createRef();
  }
  focusDiv() {
    // we're accessing "current" to get the DOM node
    this.myRef.current.focus();
  }
 
  render() {
    // attached to React elements via the ref
    return <div ref={this.myRef} />;
  }
}
 

Value of the ref differs depending on the type of the node:

  • When the ref attribute is used on an HTML element:
    • The ref receives the underlying DOM element as its current property.
  • When the ref attribute is used on a custom class component:
    • The ref receives the mounted instance of the component as its current.
    • It’s assigned null when it unmounts.
    • ref updates happen before componentDidMount or componentDidUpdate lifecycle methods.

Functional components & Refs

  • You may not use the ref attribute “on” function components. because they don’t have instances:

    <MyFunctionComponent ref={this.textInput} /> // won't work
    • You can use forwardRef to work around this.
    • createRef will always create a new ref: class-based components works(instances)
    • useRef takes care of returning the same ref each time as on the initial rendering: function components.
  • ref attribute inside a function component works as long as it’s referring to DOM el or class component

Forwarding refs

You might want to have access to a child’s DOM node from a parent component.

  • While you could add a ref to the child component, this is not ideal.
    • You’d only get the component instance instead of the DOM node
    • Won’t work on function components
  • Ref forwarding lets components opt into exposing any child component’s ref as their own. (better)

Ref forwarding is an opt-in feature that lets:

  • some components take a ref they receive
  • pass it further down (in other words, “forward” it) to a child.
// The second ref argument only exists when you define a component with
// React.forwardRef call.
const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));
 
// You can now get a ref directly to the DOM button
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
 
 

Callback refs

You could also use callback refs which are defined inline.

JSX

// When you pass a string literal, its value is HTML-unescaped.
// So these two JSX expressions are equivalent:
<MyComponent message="&lt;3" />
<MyComponent message={'<3'} />

Portals

Portals provide a first-class way to:

  • render children into a DOM node
  • that exists outside the DOM hierarchy of the parent component.

Usecase:

  • When a parent component has an overflow: hidden or z-index style.
  • For example, dialogs, hovercards, and tooltips.

Techniques

HOC

A higher-order component is a function that takes a component and returns a new component. They are a pattern that emerges from React’s compositional nature.

  • These start with a small case letter but return a container component
  • Resist the temptation to modify a component’s prototype (or otherwise mutate it) inside a HOC.
    • Instead of mutation, HOCs should use composition, by wrapping the input component in a container component.
  • Some uses
    • Pass Unrelated Props Through to the Wrapped Component
    • Wrap the Display Name for Easy Debugging

render props

Technique for sharing code between React components using a prop whose value is a function.

  • A render prop is a function prop that a component uses to know what to render.
  • You can implement most higher-order components (HOC) using a regular component with a render prop.
  • You don’t have to use a prop named render to use this pattern.

share the state or behavior that one component encapsulates to other components that need that same state.

// children attribute could have been named differently too. it's the
// render-prop
<Mouse children={mouse => (
  <p>The mouse position is {mouse.x}, {mouse.y}</p>
)}/>
// same as above
<Mouse>
  {mouse => (
    <p>The mouse position is {mouse.x}, {mouse.y}</p>
  )}
</Mouse>
 

Skipped sections

  • Integrating w other libs
  • Optimizing performance
  • Profiler
  • Strict Mode
  • Typechecking w proptypes
  • Uncontrolled components

Web Components

  • Usually when using react you’ll not be using webcomponents but can mix
  • If you are using third-party Web Components, the best solution is to write a React component that behaves as a wrapper for your Web Component.
    • Events emitted by a Web Component may not properly propagate through a React render tree. You will need to manually attach event handlers to handle these events within your React components.

Hooks

  • Hooks let you use state and other React features without writing a class.
  • Hooks allow you to reuse stateful logic without changing your component hierarchy.
  • Hooks are functions that let you “hook into” React state and lifecycle features from function components.
  • Hooks let you split one component into smaller functions based on:
    • what pieces are related (such as setting up a subscription or fetching data)
    • rather than forcing a split based on lifecycle methods. (we can make it more predictable with reducer)

useState

  • We call it inside a function component to add some local state to it.
  • Unlike this.setState, useState doesn’t merge the old and new state together.
  • State is only created the first time our component renders. During the next renders, useState gives us the current state.
  • Calling useState declares a “state variable”.
    • Normally, variables disappear when the function exits but state variables are preserved by React.

useEffect

  • Adds the ability to perform side effects from a function component.
  • It’s componentDidMount, componentDidUpdate, and componentWillUnmount unified into a single API.
  • It doesn’t block the browser from updating the screen.
  • React will apply every effect used by the component, in the order they were specified.
  • When you call useEffect, you’re telling React to run your “effect” function after flushing changes to the DOM.
    • React guarantees the DOM has been updated by the time it runs the effects.

Two kind of side effects

  • Not requiring cleanup
  • Requiring cleanup
    • If your effect returns a function, React will run it when it is time to clean up.
    • effect cleanup phase happens after every re-render, and not just once during unmounting.
    • To clean up only once (on mount and unmount), pass ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state,

useContext

useReducer

useLayoutEffect

measuring the layout

Rules

  • Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions.

Custom hooks

When we want reuse some stateful logic between components:

  • There were two options: HOC and render props.
  • Custom Hooks let you do this, but without adding more components to your tree.

Custom Hooks are more of a convention than a feature.

  • If a function’s name starts with use and it calls other Hooks, we say it is a custom Hook.
  • When we want to share logic between two JavaScript functions, we extract it to a third function.
  • Two components using the same Hook do not share state. We only share logic.