Preact

repository·main·Indexed 12 days ago

https://github.com/preactjs/preact

A fast, lightweight (4kB) React-compatible Virtual DOM library providing a modern API including hooks, functional components, and an optimized diffing algorithm. Version 11.0.0-rc.0 includes features such as createRoot, hydrateRoot, and a compatibility layer (preact-compat) for React-compatible JSX runtimes, server-side rendering (renderToString, renderToPipeableStream), and a priority-based scheduler.

Tokens
31.9K
Snippets
141
Records
165
Agent score
98%

What's inside Preact

  1. How Preact works: Components and the render() function

    main

    Preact builds user interfaces by assembling trees of components and elements.

    • Components: Functions or classes that return a description of the UI tree. These descriptions are typically written using JSX or HTM.
    • render(vnode, container): This function accepts a tree description (vnode) and creates the corresponding DOM structure inside the provided container.
    • Efficient Updates: Subsequent calls to render() with a new tree will reuse the existing structure and update it in-place. Preact calculates the difference (diffing) between the new and old structures to perform the minimum number of DOM operations required.
    import { h, render } from 'preact';
    /** @jsx h */
    
    // Initial render
    render(
    	<main>
    		<h1>Hello</h1>
    	</main>,
    	document.body
    );
    
    // Update the tree in-place
    render(
    	<main>
    		<h1>Hello World!</h1>
    	</main>,
    	document.body
    );
  2. Configure JSX factory for Preact

    main

    When using JSX, you must tell your compiler (like Babel) to use Preact's h function instead of React's createElement.

    Babel Configuration: You can use the @babel/plugin-transform-react-jsx plugin.

    TypeScript Configuration: In your tsconfig.json, you can specify the jsxFactory to automate this:

    {
      "compilerOptions": {
        "jsx": "react",
        "jsxFactory": "h"
      }
    }

    Manual Pragma: Alternatively, you can add a pragma comment at the top of individual files:

    /** @jsx h */
    import { h } from 'preact';
  3. Use preact/compat for React compatibility

    main

    The preact/compat layer provides a React-compatible API surface, allowing you to use libraries built for React within a Preact application. It exports a React namespace containing hooks, components, and utilities that mirror the React API.

    Key features include:

    • Hooks: useState, useEffect, useContext, useMemo, useCallback, etc.
    • Components: Component, PureComponent, Fragment, Suspense.
    • Utilities: createElement, render, hydrate, createPortal, memo, forwardRef.
  4. Configure CSS properties in Preact

    main

    Preact provides types for styling components via the style attribute.

    • DOMCSSProperties: A subset of CSSStyleDeclaration that excludes methods like setProperty or getPropertyValue, allowing for standard property assignment.
    • AllCSSProperties: A dictionary allowing any string key for custom properties.
    • CSSProperties: The primary interface for the style prop. It extends both AllCSSProperties and DOMCSSProperties and includes an optional cssText property for raw CSS strings.
    export type DOMCSSProperties = {
    	[key in keyof Omit<
    		CSSStyleDeclaration,
    		| 'item'
    		| 'setProperty'
    		| 'removeProperty'
    		| 'getPropertyValue'
    		| 'getPropertyPriority'
    		]?: string | number | null | undefined;
    };
    
    export type AllCSSProperties = {
    	[key: string]: string | number | null | undefined;
    };
    
    export interface CSSProperties extends AllCSSProperties, DOMCSSProperties {
    	cssText?: string | null;
    }
  5. Compatibility with React lifecycle methods

    main
    Preact's compatibility layer supports React's UNSAFE_* lifecycle methods. If a component defines UNSAFE_componentWillMount, UNSAFE_componentWillReceiveProps, or UNSAFE_componentWillUpdate, Preact will map these to the unprefixed versions (componentWillMount, etc.) to maintain compatibility with legacy React codebases.
  6. Handle DOM events with TargetedEvent and EventHandler

    main

    Preact uses a TargetedEvent<Target, TypedEvent> type to ensure that the currentTarget property of an event is correctly typed to the specific element that triggered the event.

    • TargetedEvent<Target, TypedEvent>: An extension of TypedEvent where currentTarget is explicitly typed as Target.
    • EventHandler<E>: A type for event listener functions. Preact provides specialized versions for different event categories to ensure type safety:
      • MouseEventHandler<Target>
      • KeyboardEventHandler<Target>
      • FocusEventHandler<Target>
      • SubmitEventHandler<Target>
      • DragEventHandler<Target>
      • PointerEventHandler<Target>
      • TouchEventHandler<Target>
      • WheelEventHandler<Target>
      • AnimationEventHandler<Target>
      • ClipboardEventHandler<Target>
      • CompositionEventHandler<Target>
      • ToggleEventHandler<Target> (for Popover events)
      • SnapEventHandler<Target> (for Scroll Snap events)
  7. Understand SignalLike and Signalish types

    main

    Preact introduces SignalLike and Signalish types to support reactive values.

    • SignalLike<T>: An object representing a reactive value with the following interface:
      • value: T: The current value.
      • peek(): T: Returns the current value without subscribing.
      • subscribe(fn: (value: T) => void): () => void: Subscribes a function to value changes; returns an unsubscribe function.
    • Signalish<T>: A type that accepts either a raw value of type T or a SignalLike<T>.
    • UnpackSignal<T>: A utility type that extracts the underlying value V from a SignalLike<V>, or returns T if it is not a signal.
    export interface SignalLike<T> {
    	value: T;
    	peek(): T;
    	subscribe(fn: (value: T) => void): () => void;
    }
    
    export type Signalish<T> = T | SignalLike<T>;
    
    export type UnpackSignal<T> = T extends SignalLike<infer V> ? V : T;
  8. Initialize Preact debug mode with initDebug()

    main

    Call initDebug() to enable development-only debugging features in Preact. This enables several safety checks and helpful error messages, including:

    • Component Stack Traces: Provides detailed owner stacks for errors.
    • Validation of createElement: Catches undefined components, invalid types, and incorrect ref usage.
    • Infinite Loop Protection: Detects and throws an error if a component re-renders more than 25 times consecutively.
    • Hook Safety: Ensures hooks are only called from render methods.
    • DOM Nesting Validation: Warns about improper HTML nesting (e.g., <table> inside <table> incorrectly, or <a> inside <a>).
    • Prop-Types Support: Enables checkPropTypes validation for functional components.
    • Key Uniqueness: Detects duplicate key attributes among siblings.
    • Suspense/Error Boundary Checks: Provides better error context for thrown promises and caught errors.
    • Hydration Mismatch Detection: Logs errors when SSR HTML does not match the client-side VNode tree.
    import { initDebug } from 'preact/debug';
    
    initDebug();
  9. Initialize Preact debug utilities with initDebug()

    main

    To enable Preact's debugging features, call initDebug(). This is typically done at the entry point of your application. It is also recommended to import preact/devtools to enable developer tools integration.

    import { initDebug } from './debug';
    import 'preact/devtools';
    
    initDebug();
  10. Building interactive UIs with Hooks

    main

    To manage state and build complex applications, you can use functional components combined with hooks like useState from preact/hooks. This allows components to respond to user input and trigger efficient re-renders of specific parts of the UI tree.

    import { render, h } from 'preact';
    import { useState } from 'preact/hooks';
    
    /** @jsx h */
    
    const App = () => {
    	const [input, setInput] = useState('');
    
    	return (
    		<div>
    			<p>Do you agree to the statement: "Preact is awesome"?</p>
    			<input value={input} onInput={e => setInput(e.target.value)} />
    		</div>
    	);
    };
    
    render(<App />, document.body);
  11. Configure Preact via the `options` object

    main

    Preact exposes a global options object that allows you to hook into the lifecycle of VNodes and customize certain behaviors. This is useful for debugging, telemetry, or specialized rendering logic.

    Available hooks in options:

    • vnode(vnode): Invoked whenever a VNode is created.
    • unmount(vnode): Invoked immediately before a VNode is unmounted.
    • diffed(vnode): Invoked after a VNode has rendered.
    • event(e): Intercepts events.
    • requestAnimationFrame(callback): Customizes the animation frame loop.
    • debounceRendering(cb): Customizes how rendering is debounced.
    • attr(name, value): Customize attribute serialization (useful with precompiled JSX).

    Note: Modifying options affects the entire Preact instance globally.

    import { options } from 'preact';
    
    options.vnode = (vnode) => {
      console.log('New VNode created:', vnode);
    };
    
    options.diffed = (vnode) => {
      console.log('VNode rendered:', vnode);
    };