Preact

Preact is a JavaScript library that lets you build interactive user interfaces with a reactive programming model. With MediaWiki hooks and some helper code that lets you write and use components and hooks using ES3 without much hassle, this library can be used on new Dev scripts.
It's ideal for scripts that take complete control of a piece of the document with an interactive interface with multiple subtle ways of updating the document. Declarative components with internal state make keeping the interface updated with your script's internal data easy.
For scripts that will not have lots of interactivity and only need a simple way of building DOM elements, you can look into Dorui or UI-js. Do keep in mind, though, that Preact and element-creating libraries are not competing; you can use both, if you need to create simple elements (for example, inserting to the toolbar) and for the interface. You just have to make sure not to mix them together in the same tree.
== Importing ==
== Preact vs. React ==
React and Preact are very similar libraries that are largely interoperable. This script uses the latter due to its smaller footprint, closer to HTML attributes (for instead of htmlFor, class instead of className, etc.), and, by default, using an array of children in props instead of varargs.
=== Learning React ===
Knowledge and experience is largely interchangeable between React and Preact. The actual differences are relatively few and a lot of them make no difference for regular usage of this library. However, you should still be somewhat familiar with them.
This script will probably not be very useful to you unless you have prior experience working with a React application. It's suggested you first go through a guide or the documentation.
* Here is the React tutorial, where you build a tic-tac-toe application. I do not recommend this tutorial, and instead, advise you to start with the main concepts introduction:
* React main concepts guide, a 12-chapter guide introducing you from the smallest hello world component, to updating the interface in-place by calling render multiple times, to state and complex problems like form management. This is the ideal way of being introduced to React, though it uses largely class components throughout for stateful UIs. You should supplement it with the introduction to hooks, and you should have a solid foundation to go off.
* Here is the index of the React documentation, where everything about the library can be found. You can learn more about features exposed in this library by looking at its official documentation.
* Here is the getting started guide for Preact, however it doesn't have much useful information. You may choose to skip to the "Essentials" section, where features like Components, Hooks, Forms, References, and Context are explained. Do keep in mind that class components are highly discouraged and you should favor hooks instead.
Do know that using either React or Preact in Dev scripts will be different due to the restrictions imposed by the ResourceLoader. Your script is likely to have a single file where all components reside, and you're restricted to ES3 features, so without a transpiler (webpack, rollup, etc.) you won't be able to use JSX, arrow functions, or destructuring. However, the most common uses for destructuring (useState and useReducer) have alternatives that don't need any. These will be discussed in the documentation that follows, under Hooks.
== Documentation ==
This section will document all the features that the library exports. It will only provide cursory explanations of features, providing a link to the official documentation, and go into detail if it differs from the original or is a new addition.
The features will be explained for each property that the library exposes. Keep in mind that the library is at window.dev.preact and is fired as the argument of the dev.preact MW hook.
=== .render(element, container) ===
: Documentation: render
This method renders a React tree into a container element. The first parameter must be a React element, created by calling h() with a Component or a tag name.
preact.render(
 h(App),
 document.getElementById('content')
);
=== .createElement(element, props) ===
: Documentation: createElement
: Alias: .h(element, props)
Creates an element from a tag name or a Component function. It's advised to use the shorter variant .h() instead, and keep a variable referencing it so creating elements is very short.
The type signature differs from the one used in React. While vararg children do work, from the 3rd argument onwards, it's highly discouraged. You should pass children directly in the props object as an array. You can also use child if you will only be passing a single child element.
Remember that what you must pass as children are React elements, not Node objects or Component functions. You can pass strings, though, and they'll be converted to a text node in the document.
If creating normal tags by passing a string as the first argument is ugly to you, do consider using the shorthand .tags object. You may prefer it, and it's the recommended way of creating elements with this library. Components still have to be rendered via createElement, however.
=== .cloneElement(element, props) ===
: Documentation: cloneElement
: Documentation: cloneElement (preact)
Clones a React element. This lets you take an existing element and extend it with your own props, or replace its children. You should use props.children to replace children instead of the third argument onwards. No significant changes from the original otherwise.
=== .createContext(defaultValue) ===
: Documentation: createContext
Creates a Context object that you can insert into your component tree with MyContext.Provider and consume with useContext. No significant changes from the original.
=== .toChildArray(children) ===
: Documentation: toChildArray (preact)
Utility function that lets you convert props.children into a flat array of children. This will wrap single children in an array and flatten the infinitely nested arrays that might be inside. No significant changes from the original.
=== Fragment ===
: Documentation: Fragments
The Fragment class for returning multiple elements from components or otherwise grouping react elements. You should probably use the helper .frag instead. Other than that, no significant changes from the original.
=== .frag(children) ===
This helper function lets you avoid writing h(Fragment, { children: [...] }). Since JSX is not available, you cannot use <> for fragments, so this is hopefully a reasonable alternative to use.
=== .tags ===
This is a special object that provides you with shorthands for creating HTML tags. It's a 🗲「Proxy」🗲, and properties you access in it will be functions that create an element named after the property you accessed. For example, tags.div(props) will be the equivalent of calling h('div', props).
=== .memo(Component, cmp) ===
: Documentation: memo
Wraps your function component and only re-renders it whenever the comparison function returns true. When the comparison function is not provided, a shallow props comparison is made, and if any properties between the previous and current props are different or missing, it will return true and re-render the component.
See optimizing performance in the React docs, and this blog post on when to use memo.
=== Hooks ===
Hooks are how you add state and side effects to your function components. They're imperative to making a usable interface with the library. Keep in mind that the useState and useReducer hooks deviate from their standard versions. The other hooks are equivalent to the alternatives.
There are other hooks worth talking about: useImperativeHandle and useDebugValue. These are not exposed by the library, even though, internally, they're available. This is because they depend on features the library is not bundled with. useImperativeHandle requires forwardRef, a feature from preact/compat, and useDebugValue needs a dev build of preact to be useful.
useErrorBoundary is another interesting hook. This is because it's Preact-specific, there is no React hook for it because in React it must be done with classes. Classes are greatly discouraged in this library, so this proves awfully convenient for Preact.
==== useState(initialState) ====
: Documentation: useState
The useState hook. You should be very familiar with it. However, you cannot use destructuring in dev scripts. As such, the useState function that's exposed by this library is slightly different.
useState returns an object with two properties: value and set. They're the equivalent of the first and second value of the returned array in useState, respectively.
This means that instead of destructuring into two variables, you simply have one state variable with a setter and a value property. As always, the setter function's identity is stable, and so is the state value if it wasn't updated with the setter function.
However, the identity of the object itself, is not stable. You should not use it for, say, the dependency argument in useEffect. You should use state.value instead, and it will work.
==== useReducer(reducer, initialArg, init) ====
: Documentation: useReducer
The useReducer hook. You can learn more about it in the documentation above.
Just like useState, you don't have access to destructuring, so this function returns an object { state, dispatch } instead. state and dispatch hold the same stability promises as the regular useReducer, but the object itself does not. Keep it in mind and you won't have trouble with this.
==== useEffect(effect, deps) ====
: Documentation: useEffect
The useEffect hook, the main way of introducing side effects to your components rendering. You can do data fetching in these, setting up intervals, subscriptions, or anything else. You can also return a function that will be called as cleanup. Make sure to read the documentation, this is a very important hook.
==== useMemo(fn) ====
: Documentation: useMemo
The useMemo hook. No significant changes from the original.
==== useCallback(fn) ====
: Documentation: useCallback
The useCallback hook. Useful for preventing re-renders in subcomponents! No significant changes from the original.
==== useRef(initialValue) ====
: Documentation: useRef
The useRef hook. Very useful for accessing internal DOM nodes returned by your components, or keeping around any state that you don't need your component to re-render to updates. No significant changes from the original.
==== useContext(fn) ====
: Documentation: useContext
The useContext hook. For avoiding drilling down state too much. Sorry you can't use redux yet! No significant changes from the original.
==== useLayoutEffect(fn) ====
: Documentation: useLayoutEffect
The useLayoutEffect hook. Called synchronously after DOM mutations are flushed to the document itself. You may use this hook to update the document, recalculate some value based on the new document (for example, an element's new scroll height to update its scroll position), and synchronously re-render inside the effect. This is done before the browser paints to the screen, so the user does not notice the inconsistent in-between state. This comes at the expense of being more invasive into Preact's rendering pipeline and giving it less freedom with when to execute your code, potentially adding jank or slowing down your interface. No significant changes from the original.
==== useErrorBoundary(callback) ====
: Documentation: useErrorBoundary
The useErrorBoundary hook. This is a special hook from Preact, that replaces React error boundaries and lets you use them from hooks. When used on a component, errors in its subtree will be propagated up to and caught by the error boundary. The callback will be called with the error, if provided.
The original hook returns a pair of elements [error, resetError], which means that this hook too was modified to return an object instead. It now returns an object with the shape { error, reset }.
== ==
=== Example counter script ===
This is a short program that will give you a rough idea of the things a script using Preact may do. It will be wrapped around by an IIFE, it will have a few placeholder variables as shorthands (preact, h, tags, and useState). It will also call preact.render with an App component, and listen to the dev.preact MW hook. Finally, it imports the library itself.