diff --git a/content/en/about/browser-support.md b/content/en/about/browser-support.md index d511a2ca3..37dfc77c0 100755 --- a/content/en/about/browser-support.md +++ b/content/en/about/browser-support.md @@ -1,8 +1,15 @@ --- title: Browser Support -description: Preact supports all modern browsers (Chrome, Firefox, Safari, Edge) and IE11 out of the box +description: Preact supports all modern browsers (Chrome, Firefox, Safari, Edge) out of the box --- # Browser Support -Preact supports modern browsers (Chrome, Firefox, Safari, Edge) and IE11. It works out of the box with these browsers and no additional polyfills are needed. +Preact 11.x supports the following browsers out of the box with no additional polyfills needed: + +- Chrome >= 40 +- Safari >= 9 +- Firefox >= 36 +- Edge >= 12 + +If you need to support older browsers, you can use polyfills or stick to Preact 10.x which supports back to IE11. diff --git a/content/en/guide/v11/api-reference.md b/content/en/guide/v11/api-reference.md new file mode 100644 index 000000000..1c9d8a8a7 --- /dev/null +++ b/content/en/guide/v11/api-reference.md @@ -0,0 +1,205 @@ +--- +title: API Reference +description: Learn more about all exported functions of the Preact module +--- + +# API Reference + +This page serves as a quick overview over all exported functions. + +--- + + + +--- + +## Component + +`Component` is a base class that can be extended to create stateful Preact components. + +Rather than being instantiated directly, Components are managed by the renderer and created as-needed. + +```js +import { Component } from 'preact'; + +class MyComponent extends Component { + // (see below) +} +``` + +### Component.render(props, state) + +All components must provide a `render()` function. The render function is passed the component's current props and state, and should return a Virtual DOM Element (typically a JSX "element"), an Array, or `null`. + +```jsx +import { Component } from 'preact'; + +class MyComponent extends Component { + render(props, state) { + // props is the same as this.props + // state is the same as this.state + + return

Hello, {props.name}!

; + } +} +``` + +To learn more about components and how they can be used, check out the [Components Documentation](/guide/v10/components). + +## render() + +`render(virtualDom, containerNode)` + +Render a Virtual DOM Element into a parent DOM element `containerNode`. Does not return anything. + +```jsx +// --repl +// DOM tree before render: +//
+ +import { render } from 'preact'; + +const Foo = () =>
foo
; + +render(, document.getElementById('container')); + +// After render: +//
+//
foo
+//
+``` + +The first argument must be a valid Virtual DOM Element, which represents either a component or an element. When passing a Component, it's important to let Preact do the instantiation rather than invoking your component directly, which will break in unexpected ways: + +```jsx +const App = () =>
foo
; + +// DON'T: Invoking components directly means they won't be counted as a +// VNode and hence not be able to use functionality relating to vnodes. +render(App(), rootElement); // ERROR +render(App, rootElement); // ERROR + +// DO: Passing components using h() or JSX allows Preact to render correctly: +render(h(App), rootElement); // success +render(, rootElement); // success +``` + +## hydrate() + +If you've already pre-rendered or server-side-rendered your application to HTML, Preact can bypass most rendering work when loading in the browser. This can be enabled by switching from `render()` to `hydrate()`, which skips most diffing while still attaching event listeners and setting up your component tree. This works only when used in conjunction with pre-rendering or [Server-Side Rendering](/guide/v10/server-side-rendering). + +```jsx +// --repl +import { hydrate } from 'preact'; + +const Foo = () =>
foo
; +hydrate(, document.getElementById('container')); +``` + +## h() / createElement() + +`h(type, props, ...children)` + +Returns a Virtual DOM Element with the given `props`. Virtual DOM Elements are lightweight descriptions of a node in your application's UI hierarchy, essentially an object of the form `{ type, props }`. + +After `type` and `props`, any remaining parameters are collected into a `children` property. +Children may be any of the following: + +- Scalar values (string, number, boolean, null, undefined, etc) +- Nested Virtual DOM Elements +- Infinitely nested Arrays of the above + +```js +import { h } from 'preact'; + +h('div', { id: 'foo' }, 'Hello!'); +//
Hello!
+ +h('div', { id: 'foo' }, 'Hello', null, ['Preact!']); +//
Hello Preact!
+ +h('div', { id: 'foo' }, h('span', null, 'Hello!')); +//
Hello!
+``` + +## toChildArray + +This helper function converts a `props.children` value to a flattened Array regardless of its structure or nesting. If `props.children` is already an array, a copy is returned. This function is useful in cases where `props.children` may not be an array, which can happen with certain combinations of static and dynamic expressions in JSX. + +For Virtual DOM Elements with a single child, `props.children` is a reference to the child. When there are multiple children, `props.children` is always an Array. The `toChildArray` helper provides a way to consistently handle all cases. + +```jsx +import { toChildArray } from 'preact'; + +function Foo(props) { + const count = toChildArray(props.children).length; + return
I have {count} children
; +} + +// props.children is "bar" +render(bar, container); + +// props.children is [

A

,

B

] +render( + +

A

+

B

+
, + container +); +``` + +## cloneElement + +`cloneElement(virtualElement, props, ...children)` + +This function allows you to create a shallow copy of a Virtual DOM Element. +It's generally used to add or overwrite `props` of an element: + +```jsx +function Linkout(props) { + // add target="_blank" to the link: + return cloneElement(props.children, { target: '_blank' }); +} +render( + + home + +); +// home +``` + +## createContext + +See the section in the [Context documentation](/guide/v10/context#createcontext). + +## createRef + +Provides a way to reference an element or component once it has been rendered. + +See the [References documentation](/guide/v10/refs#createref) for more details. + +## Fragment + +A special kind of component that can have children, but is not rendered as a DOM element. +Fragments make it possible to return multiple sibling children without needing to wrap them in a DOM container: + +```jsx +// --repl +import { Fragment, render } from 'preact'; + +render( + +
A
+
B
+
C
+
, + document.getElementById('container') +); +// Renders: +//
; + +// Renders:
My name is John Doe.
+render(App, document.body); +``` + +> Note in earlier versions they were known as `"Stateless Components"`. This doesn't hold true anymore with the [hooks-addon](/guide/v10/hooks). + +## Class Components + +Class components can have state and lifecycle methods. The latter are special methods, that will be called when a component is attached to the DOM or destroyed for example. + +Here we have a simple class component called `` that displays the current time: + +```jsx +// --repl +import { Component, render } from 'preact'; + +// --repl-before +class Clock extends Component { + constructor() { + super(); + this.state = { time: Date.now() }; + } + + // Lifecycle: Called whenever our component is created + componentDidMount() { + // update time every second + this.timer = setInterval(() => { + this.setState({ time: Date.now() }); + }, 1000); + } + + // Lifecycle: Called just before our component will be destroyed + componentWillUnmount() { + // stop when not renderable + clearInterval(this.timer); + } + + render() { + let time = new Date(this.state.time).toLocaleTimeString(); + return {time}; + } +} +// --repl-after +render(, document.getElementById('app')); +``` + +### Lifecycle Methods + +In order to have the clock's time update every second, we need to know when `` gets mounted to the DOM. _If you've used HTML5 Custom Elements, this is similar to the `attachedCallback` and `detachedCallback` lifecycle methods._ Preact invokes the following lifecycle methods if they are defined for a Component: + +| Lifecycle method | When it gets called | +| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| `componentWillMount()` | (deprecated) before the component gets mounted to the DOM | +| `componentDidMount()` | after the component gets mounted to the DOM | +| `componentWillUnmount()` | prior to removal from the DOM | +| `componentWillReceiveProps(nextProps, nextContext)` | before new props get accepted _(deprecated)_ | +| `getDerivedStateFromProps(nextProps, prevState)` | just before `shouldComponentUpdate`. Return object to update state or `null` to skip update. Use with care. | +| `shouldComponentUpdate(nextProps, nextState, nextContext)` | before `render()`. Return `false` to skip render | +| `componentWillUpdate(nextProps, nextState, nextContext)` | before `render()` _(deprecated)_ | +| `getSnapshotBeforeUpdate(prevProps, prevState)` | called just before `render()`. return value is passed to `componentDidUpdate`. | +| `componentDidUpdate(prevProps, prevState, snapshot)` | after `render()` | + +Here's a visual overview of how they relate to each other (originally posted in [a tweet](https://web.archive.org/web/20191118010106/https://twitter.com/dan_abramov/status/981712092611989509) by Dan Abramov): + +![Diagram of component lifecycle methods](/guide/components-lifecycle-diagram.png) + +### Error Boundaries + +An error boundary is a component that implements either `componentDidCatch()` or the static method `getDerivedStateFromError()` (or both). These are special methods that allow you to catch any errors that happen during rendering and are typically used to provide nicer error messages or other fallback content and save information for logging purposes. It's important to note that error boundaries cannot catch all errors and those thrown in event handlers or asynchronous code (like a `fetch()` call) need to be handled separately. + +When an error is caught, we can use these methods to react to any errors and display a nice error message or any other fallback content. + +```jsx +// --repl +import { Component, render } from 'preact'; +// --repl-before +class ErrorBoundary extends Component { + constructor() { + super(); + this.state = { errored: false }; + } + + static getDerivedStateFromError(error) { + return { errored: true }; + } + + componentDidCatch(error, errorInfo) { + errorReportingService(error, errorInfo); + } + + render(props, state) { + if (state.errored) { + return

Something went badly wrong

; + } + return props.children; + } +} +// --repl-after +render(, document.getElementById('app')); +``` + +## Fragments + +A `Fragment` allows you to return multiple elements at once. They solve the limitation of JSX where every "block" must have a single root element. You'll often encounter them in combination with lists, tables or with CSS flexbox where any intermediate element would otherwise affect styling. + +```jsx +// --repl +import { Fragment, render } from 'preact'; + +function TodoItems() { + return ( + +
  • A
  • +
  • B
  • +
  • C
  • +
    + ); +} + +const App = ( +
      + +
    • D
    • +
    +); + +render(App, container); +// Renders: +//
      +//
    • A
    • +//
    • B
    • +//
    • C
    • +//
    • D
    • +//
    +``` + +Note that most modern transpilers allow you to use a shorter syntax for `Fragments`. The shorter one is a lot more common and is the one you'll typically encounter. + +```jsx +// This: +const Foo = foo; +// ...is the same as this: +const Bar = <>foo; +``` + +You can also return arrays from your components: + +```jsx +function Columns() { + return [Hello, World]; +} +``` + +Don't forget to add keys to `Fragments` if you create them in a loop: + +```jsx +function Glossary(props) { + return ( +
    + {props.items.map(item => ( + // Without a key, Preact has to guess which elements have + // changed when re-rendering. + +
    {item.term}
    +
    {item.description}
    +
    + ))} +
    + ); +} +``` diff --git a/content/en/guide/v11/context.md b/content/en/guide/v11/context.md new file mode 100644 index 000000000..72ae030fb --- /dev/null +++ b/content/en/guide/v11/context.md @@ -0,0 +1,232 @@ +--- +title: Context +description: Context allows you to pass props through intermediate components. This documents describes both the new and the old API +--- + +# Context + +Context is a way to pass data through the component tree without having to pass it through every component in-between via props. In a nutshell, it allows components anywhere in the hierarchy to subscribe to a value and get notified when it changes, bringing pub-sub-style updates to Preact. + +It's not uncommon to run into situations in which a value from a grandparent component (or higher) needs to be passed down to a child, often without the intermediate component needing it. This process of passing down props is often referred to as "prop drilling" and can be cumbersome, error-prone, and just plain repetitive, especially as the application grows and more values have to be passed through more layers. This is one of the key issues Context aims to address by providing a way for a child to subscribe to a value higher up in the component tree, accessing the value without it being passed down as a prop. + +There are two ways to use context in Preact: via the newer `createContext` API and the legacy context API. These days there's very few reasons to ever reach for the legacy API but it's documented here for completeness. + +--- + + + +--- + +## Modern Context API + +### Creating a Context + +To create a new context, we use the `createContext` function. This function takes an initial state as an argument and returns an object with two component properties: `Provider`, to make the context available to descendants, and `Consumer`, to access the context value (primarily in class components). + +```jsx +import { createContext } from 'preact'; + +export const Theme = createContext('light'); +export const User = createContext({ name: 'Guest' }); +export const Locale = createContext(null); +``` + +### Setting up a Provider + +Once we've created a context, we must make it available to descendants using the `Provider` component. The `Provider` must be given a `value` prop, representing the initial value of the context. + +> The initial value set from `createContext` is only used in the absence of a `Provider` above the consumer in the tree. This may be helpful for testing components in isolation, as it avoids the need for creating a wrapping `Provider` around your component. + +```jsx +import { createContext } from 'preact'; + +export const Theme = createContext('light'); + +function App() { + return ( + + + + ); +} +``` + +> **Tip:** You can have multiple providers of the same context throughout your app but only the closest one to the consumer will be used. + +### Using the Context + +There are three ways to consume a context, largely dependent on your preferred component style: `static contextType` (class components), the `useContext` hook (function components/hooks), and `Context.Consumer` (all components), . + + + +```jsx +// --repl +import { render, createContext, Component } from 'preact'; + +const SomeComponent = props => props.children; +// --repl-before +const ThemePrimary = createContext('#673ab8'); + +class ThemedButton extends Component { + static contextType = ThemePrimary; + + render() { + const theme = this.context; + return ; + } +} + +function App() { + return ( + + + + + + ); +} +// --repl-after +render(, document.getElementById('app')); +``` + +```jsx +// --repl +import { render, createContext } from 'preact'; +import { useContext } from 'preact/hooks'; + +const SomeComponent = props => props.children; +// --repl-before +const ThemePrimary = createContext('#673ab8'); + +function ThemedButton() { + const theme = useContext(ThemePrimary); + return ; +} + +function App() { + return ( + + + + + + ); +} +// --repl-after +render(, document.getElementById('app')); +``` + +```jsx +// --repl +import { render, createContext } from 'preact'; + +const SomeComponent = props => props.children; +// --repl-before +const ThemePrimary = createContext('#673ab8'); + +function ThemedButton() { + return ( + + {theme => } + + ); +} + +function App() { + return ( + + + + + + ); +} +// --repl-after +render(, document.getElementById('app')); +``` + + + +### Updating the Context + +Static values can be useful, but more often than not, we want to be able to update the context value dynamically. To do so, we leverage standard component state mechanisms: + +```jsx +// --repl +import { render, createContext } from 'preact'; +import { useContext, useState } from 'preact/hooks'; + +const SomeComponent = props => props.children; +// --repl-before +const ThemePrimary = createContext(null); + +function ThemedButton() { + const { theme } = useContext(ThemePrimary); + return ; +} + +function ThemePicker() { + const { theme, setTheme } = useContext(ThemePrimary); + return ( + setTheme(e.currentTarget.value)} + /> + ); +} + +function App() { + const [theme, setTheme] = useState('#673ab8'); + return ( + + + + {' - '} + + + + ); +} +// --repl-after +render(, document.getElementById('app')); +``` + +## Legacy Context API + +This API is considered legacy and should be avoided in new code, it has known issues and only exists for backwards-compatibility reasons. + +One of the key differences between this API and the new one is that this API cannot update a child when a component in-between the child and the provider aborts rendering via `shouldComponentUpdate`. When this happens, the child **will not** received the updated context value, often resulting in tearing (part of the UI using the new value, part using the old). + +To pass down a value through the context, a component needs to have the `getChildContext` method, returning the intended context value. Descendants can then access the context via the second argument in function components or `this.context` in class-based components. + +```jsx +// --repl +import { render } from 'preact'; + +const SomeOtherComponent = props => props.children; +// --repl-before +function ThemedButton(_props, context) { + return ; +} + +class App extends Component { + getChildContext() { + return { + theme: '#673ab8' + }; + } + + render() { + return ( +
    + + + +
    + ); + } +} +// --repl-after +render(, document.getElementById('app')); +``` diff --git a/content/en/guide/v11/debugging.md b/content/en/guide/v11/debugging.md new file mode 100644 index 000000000..5f829f7b6 --- /dev/null +++ b/content/en/guide/v11/debugging.md @@ -0,0 +1,222 @@ +--- +title: Debugging Preact Apps +description: How to debug Preact applications when something goes wrong +--- + +# Debugging Preact Apps + +Preact ships with a lot of tools to make debugging easier. They're packaged in a single import and can be included by importing `preact/debug`. + +These include integration with our own [Preact Devtools] Extension for Chrome and Firefox. + +We'll print a warning or an error whenever we detect something wrong like incorrect nesting in `` elements. + +--- + + + +--- + +## Installation + +The [Preact Devtools] can be installed in the extension store of your browser. + +- [For Chrome](https://chrome.google.com/webstore/detail/preact-developer-tools/ilcajpmogmhpliinlbcdebhbcanbghmd) +- [For Firefox](https://addons.mozilla.org/en-US/firefox/addon/preact-devtools/) +- [For Edge](https://microsoftedge.microsoft.com/addons/detail/hdkhobcafnfejjieimdkmjaiihkjpmhk) + +Once installed we need to import `preact/debug` somewhere to initialize the connection to the extension. Make sure that this import is **the first** import in your whole app. + +> `@preact/preset-vite` includes the `preact/debug` package automatically. You can safely skip the setup & strip steps if you're using it! + +Here is an example of how your main entry file to your application may look like. + +```jsx +// Must be the first import +import 'preact/debug'; +import { render } from 'preact'; +import App from './components/App'; + +render(, document.getElementById('root')); +``` + +### Strip devtools from production + +Most bundlers allow you strip out code when they detect that a branch inside an `if`-statement will never be hit. We can use this to only include `preact/debug` during development and save those precious bytes in a production build. + +```jsx +// Must be the first import +if (process.env.NODE_ENV === 'development') { + // Must use require here as import statements are only allowed + // to exist at top-level. + require('preact/debug'); +} + +import { render } from 'preact'; +import App from './components/App'; + +render(, document.getElementById('root')); +``` + +Make sure to set the `NODE_ENV` variable to the correct value in your build tool. + +## Debug Warnings and Errors + +Sometimes you may get warnings or errors when Preact detects invalid code. These should be fixed to ensure that your app works flawlessly. + +### `undefined` parent passed to `render()` + +This means that the code is trying to render your app into nothing instead of a DOM node. It's the difference between: + +```jsx +// What Preact received +render(, undefined); + +// vs what it expected +render(, actualDomNode); +``` + +The main reason this error occurs is that the DOM node isn't present when the `render()` function is called. Make sure it exists. + +### `undefined` component passed to `createElement()` + +Preact will throw this error whenever you pass `undefined` instead of a component. The common cause for this one is mixing up `default` and `named` exports. + +```jsx +// app.js +export default function App() { + return
    Hello World
    ; +} + +// index.js: Wrong, because `app.js` doesn't have a named export +import { App } from './app'; +render(, dom); +``` + +The same error will be thrown when it's the other way around. When you declare a `named` export and are trying to use it as a `default` export. One quick way to check this (in case your editor won't do it already), is to just log out the import: + +```jsx +// app.js +export function App() { + return
    Hello World
    ; +} + +// index.js +import App from './app'; + +console.log(App); +// Logs: { default: [Function] } instead of the component +``` + +### Passed a JSX literal as JSX twice + +Passing a JSX-Literal or Component into JSX again is invalid and will trigger this error. + +```jsx +const Foo =
    foo
    ; +// Invalid: Foo already contains a JSX-Element +render(, dom); +``` + +To fix this, we can just pass the variable directly: + +```jsx +const Foo =
    foo
    ; +render(Foo, dom); +``` + +### Improper nesting of table detected + +HTML parsers have very strict rules on how tables should be structured, deviating from which will lead to rendering errors that can be hard to debug. To help with this, Preact can detect improper nesting in a number of situations and will print warnings to catch this early. To learn more about how tables should be structured we can highly recommend [the MDN documentation](https://developer.mozilla.org/en-US/docs/Learn/HTML/Tables/Basics). + +> **Note:** In this context, "strict" is referring to the _output_ of the HTML parser, not the _input_. Browsers are quite forgiving and try to correct invalid HTML where they can to ensure that pages can still be displayed. However, for VDOM libraries like Preact this can lead to issues as the input content might not match the output once the browser has corrected it which Preact will not be made aware of. +> +> For example, `
    ` elements must always be a child of ``, ``, or `` elements per the spec, but if you were to write a `` directly inside of a `
    `, the browser will attempt to correct this by wrapping it in a `` element for you. Preact will therefore expect the DOM structure to be `
    ` but the real DOM constructed by the browser would be `
    `. + +### Invalid `ref`-property + +When the `ref` property contains something unexpected we'll throw this error. This includes string-based `refs` that have been deprecated a while ago. + +```jsx +// valid +
    {/* ... */)}} /> + +// valid +const ref = createRef(); +
    + +// Invalid +
    +``` + +### Invalid event handler + +Sometimes you'll may accidentally pass a wrong value to an event handler. They must always be a `function` or `null` if you want to remove it. All other types are invalid. + +```jsx +// valid +
    console.log("click")} /> + +// invalid +
    +``` + +### Hook can only be invoked from render methods + +This error occurs when you try to use a hook outside of a component. They are only supported inside a function component. + +```jsx +// Invalid, must be used inside a component +const [value, setValue] = useState(0); + +// valid +function Foo() { + const [value, setValue] = useState(0); + return ; +} +``` + +### Getting `vnode.[property]` is deprecated + +With Preact X we did some breaking changes to our internal `vnode` shape. + +| Preact 8.x | Preact 10.x | +| ------------------ | ---------------------- | +| `vnode.nodeName` | `vnode.type` | +| `vnode.attributes` | `vnode.props` | +| `vnode.children` | `vnode.props.children` | + +### Found children with the same key + +One unique aspect about virtual-dom based libraries is that they have to detect when a children is moved around. However to know which child is which, we need to flag them somehow. _This is only necessary when you're creating children dynamically._ + +```jsx +// Both children will have the same key "A" +
    + {['A', 'A'].map(char => ( +

    {char}

    + ))} +
    +``` + +The correct way to do it is to give them unique keys. In most cases the data you're iterating over will have some form of `id`. + +```jsx +const persons = [ + { name: 'John', age: 22 }, + { name: 'Sarah', age: 24 } +]; + +// Somewhere later in your component +
    + {persons.map(({ name, age }) => { + return ( +

    + {name}, Age: {age} +

    + ); + })} +
    ; +``` + +[preact devtools]: https://preactjs.github.io/preact-devtools/ diff --git a/content/en/guide/v11/differences-to-react.md b/content/en/guide/v11/differences-to-react.md new file mode 100755 index 000000000..3eba449d7 --- /dev/null +++ b/content/en/guide/v11/differences-to-react.md @@ -0,0 +1,224 @@ +--- +title: Differences to React +description: What are the differences between Preact and React. This document describes them in detail +--- + +# Differences to React + +Preact is not intended to be a reimplementation of React. There are differences. Many of these differences are trivial, or can be completely removed by using [preact/compat], which is a thin layer over Preact that attempts to achieve 100% compatibility with React. + +The reason Preact does not attempt to include every single feature of React is in order to remain **small** and **focused** - otherwise it would make more sense to simply submit optimizations to the React project, which is already a very complex and well-architected codebase. + +--- + + + +--- + +## Main differences + +The main difference between Preact and React is that Preact does not implement a synthetic event system for size and performance reasons. Preact uses the browser's standard `addEventListener` to register event handlers, which means event naming and behavior works the same in Preact as it does in plain JavaScript / DOM. See [MDN's Event Reference] for a full list of DOM event handlers. + +Standard browser events work very similarly to how events work in React, with a few small differences. In Preact: + +- events don't bubble up through `` components +- standard `onInput` should be used instead of React's `onChange` for form inputs (**only if `preact/compat` is not used**) +- standard `onDblClick` should be used instead of React's `onDoubleClick` (**only if `preact/compat` is not used**) +- `onSearch` should generally be used for ``, since the clear "x" button does not fire `onInput` in IE11 + +Another notable difference is that Preact follows the DOM specification more closely. Custom elements are supported like any other element, and custom events are supported with case-sensitive names (as they are in the DOM). + +## Version Compatibility + +For both preact and [preact/compat], version compatibility is measured against the _current_ and _previous_ major releases of React. When new features are announced by the React team, they may be added to Preact's core if it makes sense given the [Project Goals]. This is a fairly democratic process, constantly evolving through discussion and decisions made in the open, using issues and pull requests. + +> Thus, the website and documentation reflect React `15.x` through `17.x`, with some `18.x` and `19.x` additions, when discussing compatibility or making comparisons. + +## Debug messages and errors + +Our flexible architecture allows addons to enhance the Preact experience in any way they want. One of those addons is `preact/debug` which adds [helpful warnings and errors](/guide/v10/debugging) and attaches the [Preact Developer Tools](https://preactjs.github.io/preact-devtools/) browser extension, if installed. Those guide you when developing Preact applications and make it a lot easier to inspect what's going on. You can enable them by adding the relevant import statement: + +```js +import 'preact/debug'; // <-- Add this line at the top of your main entry file +``` + +This is different from React which requires a bundler being present that strips out debugging messages at build time by checking for `NODE_ENV != "production"`. + +## Features unique to Preact + +Preact actually adds a few convenient features inspired by work in the (P)React community: + +### Native support for ES Modules + +Preact was built with ES Modules in mind from the beginning, and was one of the first frameworks to support them. You can load Preact via the `import` keyword directly in browsers without having it to pass through a bundler first. + +### Arguments in `Component.render()` + +For convenience, we pass `this.props` and `this.state` to the `render()` method on class components. Take a look at this component which uses one prop and one state property. + +```jsx +// Works in both Preact and React +class Foo extends Component { + state = { age: 1 }; + + render() { + return ( +
    + Name: {this.props.name}, Age: {this.state.age} +
    + ); + } +} +``` + +In Preact this can be also written like this: + +```jsx +// Only works in Preact +class Foo extends Component { + state = { age: 1 }; + + render({ name }, { age }) { + return ( +
    + Name: {name}, Age: {age} +
    + ); + } +} +``` + +Both snippets render the exact same thing, render arguments are provided for convenience. + +### Raw HTML attribute/property names + +Preact aims to closely match the DOM specification supported by all major browsers. When applying `props` to an element, Preact _detects_ whether each prop should be set as a property or HTML attribute. This makes it possible to set complex properties on Custom Elements, but it also means you can use attribute names like `class` in JSX: + +```jsx +// This: +
    + +// ...is the same as: +
    +``` + +Most Preact developers prefer to use `class` instead of `className` as it's shorter to write but both are supported. + +### SVG inside JSX + +SVG is pretty interesting when it comes to the names of its properties and attributes. Some properties (and their attributes) on SVG objects are camelCased (e.g. [clipPathUnits on a clipPath element](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/clipPath#Attributes)), some attributes are kebab-case (e.g. [clip-path on many SVG elements](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/Presentation)), and other attributes (usually ones inherited from the DOM, e.g. `oninput`) are all lowercase. + +Preact applies SVG attributes as-written. This means you can copy and paste unmodified SVG snippets right into your code and have them work out of the box. This allows greater interoperability with tools designers tend to use to generate icons or SVG illustrations. + +```jsx +// React + + + +// Preact (note stroke-width and stroke-linejoin) + + + +``` + +If you're coming from React, you may be used to specifying all attributes in camelCase. You can continue to use always-camelCase SVG attribute names by adding [preact/compat] to your project, which mirrors the React API and normalizes these attributes. + +### Use `onInput` instead of `onChange` + +Largely for historical reasons, the semantics of React's `onChange` event are actually the same as the `onInput` event provided by browsers, which is supported everywhere. The `input` event is the best-suited event for the majority of cases where you want to react when a form control is modified. In Preact core, `onChange` is the standard [DOM change event](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event) that gets fired when an element's value is _committed_ by the user. + +```jsx +// React + console.log(e.currentTarget.value)} /> + +// Preact + console.log(e.currentTarget.value)} /> +``` + +If you're using [preact/compat], most `onChange` events are internally converted to `onInput` to emulate React's behavior. This is one of the tricks we use to ensure maximum compatibility with the React ecosystem. + +### JSX Constructor + +JSX is a syntax extension for JavaScript that is converted to nested function calls. The idea of using these nested calls to build up tree structures long predates JSX, and was previously popularized in JavaScript by the [hyperscript] project. This approach has value well beyond the scope of the React ecosystem, so Preact promotes the original generalized community-standard. For a more in-depth discussion of JSX and its relationship to Hyperscript, [read this article on how JSX works](https://jasonformat.com/wtf-is-jsx). + +**Source:** (JSX) + +```jsx + + Home + +``` + +**Output:** + +```js +// Preact: +h('a', { href: '/' }, h('span', null, 'Home')); + +// React: +React.createElement( + 'a', + { href: '/' }, + React.createElement('span', null, 'Home') +); +``` + +Ultimately, if you're looking at the generated output code for a Preact application, it's clear that a shorter un-namespaced "JSX pragma" is both easier to read _and_ more suitable for optimizations like minification. In most Preact apps you'll encounter `h()`, though it doesn't really matter which name you use since a `createElement` alias export is also provided. + +### No contextTypes needed + +The legacy `Context` API requires Components to declare specific properties using React's `contextTypes` or `childContextTypes` in order to receive those values. Preact does not have this requirement: all Components receive all `context` properties produced by `getChildContext()` by default. + +## Features exclusive to `preact/compat` + +`preact/compat` is our **compat**ibility layer that translates React code to Preact. For existing React users this can be an easy way to try out Preact without changing any of your code, by [setting up a few aliases](/guide/v10/getting-started#aliasing-react-to-preact) in your bundler configuration. + +### Children API + +The `Children` API is a specialized set of methods for working with the value of `props.children`. For Preact this is generally unnecessary, and we recommend using the built-in array methods instead. In Preact, `props.children` is either a Virtual DOM node, an empty value like `null`, or an Array of Virtual DOM nodes. The first two cases are the simplest and most common, since it's possible to use or return `children` as-is: + +```jsx +// React: +function App(props) { + return ; +} + +// Preact: use props.children directly: +function App(props) { + return ; +} +``` + +For specialized cases where you need to iterate over the children passed to a component, Preact provides a `toChildArray()` method that accepts any `props.children` value and returns a flattened and normalized Array of Virtual DOM nodes. + +```jsx +// React +function App(props) { + const cols = Children.count(props.children); + return
    {props.children}
    ; +} + +// Preact +function App(props) { + const cols = toChildArray(props.children).length; + return
    {props.children}
    ; +} +``` + +A React-compatible `Children` API is available from `preact/compat` to make integration with existing component libraries seamless. + +### Specialised Components + +[preact/compat] ships with specialised components that are not necessary for every app. These include + +- [PureComponent](/guide/v10/switching-to-preact#purecomponent): Only updates if `props` or `state` have changed +- [memo](/guide/v10/switching-to-preact#memo): Similar in spirit to `PureComponent` but allows to use a custom comparison function +- [forwardRef](/guide/v10/switching-to-preact#forwardref): Supply a `ref` to a specified child component. +- [Portals](/guide/v10/switching-to-preact#portals): Continues rendering the current tree into a different DOM container +- [Suspense](/guide/v10/switching-to-preact#suspense-experimental): **experimental** Allows to display fallback content in case the tree is not ready +- [lazy](/guide/v10/switching-to-preact#suspense-experimental): **experimental** Lazy load async code and mark a tree as ready/not ready accordingly. + +[project goals]: /about/project-goals +[hyperscript]: https://github.com/dominictarr/hyperscript +[preact/compat]: /guide/v10/switching-to-preact +[mdn's event reference]: https://developer.mozilla.org/en-US/docs/Web/Events diff --git a/content/en/guide/v11/forms.md b/content/en/guide/v11/forms.md new file mode 100755 index 000000000..ff0410aaa --- /dev/null +++ b/content/en/guide/v11/forms.md @@ -0,0 +1,452 @@ +--- +title: Forms +description: Forms and form controls allow you to collect user input in your application and is a fundamental building block of most web applications +--- + +# Forms + +Forms in Preact work in the same way as they do in HTML & JS: you render controls, attach event listeners, and submit information. + +--- + + + +--- + +## Basic Form Controls + +Often you'll want to collect user input in your application, and this is where ``, `