diff --git a/compat/src/index.js b/compat/src/index.js index f08b89b03d..9e8a38da39 100644 --- a/compat/src/index.js +++ b/compat/src/index.js @@ -25,15 +25,9 @@ import { memo } from './memo'; import { forwardRef } from './forwardRef'; import { Children } from './Children'; import { Suspense, lazy } from './suspense'; -import { SuspenseList } from './suspense-list'; import { createPortal } from './portals'; import { is } from './util'; -import { - hydrate, - render, - REACT_ELEMENT_TYPE, - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED -} from './render'; +import { hydrate, render, REACT_ELEMENT_TYPE } from './render'; const version = '17.0.2'; // trick libraries to think we are react @@ -95,6 +89,7 @@ function cloneElement(element) { * @param {import('./internal').PreactElement} container * @returns {boolean} */ +// TODO: replaced with root.unmount() function unmountComponentAtNode(container) { if (container._children) { preactRender(null, container); @@ -116,16 +111,6 @@ function findDOMNode(component) { ); } -/** - * Deprecated way to control batched rendering inside the reconciler, but we - * already schedule in batches inside our rendering code - * @template Arg - * @param {(arg: Arg) => void} callback function that triggers the updated - * @param {Arg} [arg] Optional argument that can be passed to the callback - */ -// eslint-disable-next-line camelcase -const unstable_batchedUpdates = (callback, arg) => callback(arg); - /** * In React, `flushSync` flushes the entire tree and forces a rerender. It's * implmented here as a no-op. @@ -237,13 +222,9 @@ export { memo, forwardRef, flushSync, - // eslint-disable-next-line camelcase - unstable_batchedUpdates, StrictMode, Suspense, - SuspenseList, - lazy, - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED + lazy }; // React copies the named exports to the default one. @@ -286,10 +267,7 @@ export default { memo, forwardRef, flushSync, - unstable_batchedUpdates, StrictMode, Suspense, - SuspenseList, - lazy, - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED + lazy }; diff --git a/compat/src/render.js b/compat/src/render.js index 62dcef0c7e..54ecdfc5df 100644 --- a/compat/src/render.js +++ b/compat/src/render.js @@ -39,42 +39,11 @@ const IS_DOM = typeof document !== 'undefined'; // Input types for which onchange should not be converted to oninput. // type="file|checkbox|radio", plus "range" in IE11. // (IE11 doesn't support Symbol, which we use here to turn `rad` into `ra` which matches "range") -const onChangeInputType = type => - (typeof Symbol != 'undefined' && typeof Symbol() == 'symbol' - ? /fil|che|rad/ - : /fil|che|ra/ - ).test(type); +const onChangeInputType = type => /fil|che|ra/.test(type); // Some libraries like `react-virtualized` explicitly check for this. Component.prototype.isReactComponent = {}; -// `UNSAFE_*` lifecycle hooks -// Preact only ever invokes the unprefixed methods. -// Here we provide a base "fallback" implementation that calls any defined UNSAFE_ prefixed method. -// - If a component defines its own `componentDidMount()` (including via defineProperty), use that. -// - If a component defines `UNSAFE_componentDidMount()`, `componentDidMount` is the alias getter/setter. -// - If anything assigns to an `UNSAFE_*` property, the assignment is forwarded to the unprefixed property. -// See https://github.com/preactjs/preact/issues/1941 -[ - 'componentWillMount', - 'componentWillReceiveProps', - 'componentWillUpdate' -].forEach(key => { - Object.defineProperty(Component.prototype, key, { - configurable: true, - get() { - return this['UNSAFE_' + key]; - }, - set(v) { - Object.defineProperty(this, key, { - configurable: true, - writable: true, - value: v - }); - } - }); -}); - /** * Proxy render() since React returns a Component reference. * @param {import('./internal').VNode} vnode VNode tree to render @@ -250,16 +219,6 @@ options.vnode = vnode => { if (oldVNodeHook) oldVNodeHook(vnode); }; -// Only needed for react-relay -let currentComponent; -const oldBeforeRender = options._render; -options._render = function (vnode) { - if (oldBeforeRender) { - oldBeforeRender(vnode); - } - currentComponent = vnode._component; -}; - const oldDiffed = options.diffed; /** @type {(vnode: import('./internal').VNode) => void} */ options.diffed = function (vnode) { @@ -278,34 +237,4 @@ options.diffed = function (vnode) { ) { dom.value = props.value == null ? '' : props.value; } - - currentComponent = null; -}; - -// This is a very very private internal function for React it -// is used to sort-of do runtime dependency injection. -export const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = { - ReactCurrentDispatcher: { - current: { - readContext(context) { - return currentComponent._globalContext[context._id].props.value; - }, - useCallback, - useContext, - useDebugValue, - useDeferredValue, - useEffect, - useId, - useImperativeHandle, - useInsertionEffect, - useLayoutEffect, - useMemo, - // useMutableSource, // experimental-only and replaced by uSES, likely not worth supporting - useReducer, - useRef, - useState, - useSyncExternalStore, - useTransition - } - } }; diff --git a/compat/src/suspense-list.d.ts b/compat/src/suspense-list.d.ts deleted file mode 100644 index caa1eb6bff..0000000000 --- a/compat/src/suspense-list.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Component, ComponentChild, ComponentChildren } from '../../src'; - -// -// SuspenseList -// ----------------------------------- - -export interface SuspenseListProps { - children?: ComponentChildren; - revealOrder?: 'forwards' | 'backwards' | 'together'; -} - -export class SuspenseList extends Component { - render(): ComponentChild; -} diff --git a/compat/src/suspense-list.js b/compat/src/suspense-list.js deleted file mode 100644 index 5e5d750a08..0000000000 --- a/compat/src/suspense-list.js +++ /dev/null @@ -1,127 +0,0 @@ -import { Component, toChildArray } from 'preact'; -import { suspended } from './suspense.js'; - -// Indexes to linked list nodes (nodes are stored as arrays to save bytes). -const SUSPENDED_COUNT = 0; -const RESOLVED_COUNT = 1; -const NEXT_NODE = 2; - -// Having custom inheritance instead of a class here saves a lot of bytes. -export function SuspenseList() { - this._next = null; - this._map = null; -} - -// Mark one of child's earlier suspensions as resolved. -// Some pending callbacks may become callable due to this -// (e.g. the last suspended descendant gets resolved when -// revealOrder === 'together'). Process those callbacks as well. -const resolve = (list, child, node) => { - if (++node[RESOLVED_COUNT] === node[SUSPENDED_COUNT]) { - // The number a child (or any of its descendants) has been suspended - // matches the number of times it's been resolved. Therefore we - // mark the child as completely resolved by deleting it from ._map. - // This is used to figure out when *all* children have been completely - // resolved when revealOrder is 'together'. - list._map.delete(child); - } - - // If revealOrder is falsy then we can do an early exit, as the - // callbacks won't get queued in the node anyway. - // If revealOrder is 'together' then also do an early exit - // if all suspended descendants have not yet been resolved. - if ( - !list.props.revealOrder || - (list.props.revealOrder[0] === 't' && list._map.size) - ) { - return; - } - - // Walk the currently suspended children in order, calling their - // stored callbacks on the way. Stop if we encounter a child that - // has not been completely resolved yet. - node = list._next; - while (node) { - while (node.length > 3) { - node.pop()(); - } - if (node[RESOLVED_COUNT] < node[SUSPENDED_COUNT]) { - break; - } - list._next = node = node[NEXT_NODE]; - } -}; - -// Things we do here to save some bytes but are not proper JS inheritance: -// - call `new Component()` as the prototype -// - do not set `Suspense.prototype.constructor` to `Suspense` -SuspenseList.prototype = new Component(); - -SuspenseList.prototype._suspended = function (child) { - const list = this; - const delegated = suspended(list._vnode); - - let node = list._map.get(child); - node[SUSPENDED_COUNT]++; - - return unsuspend => { - const wrappedUnsuspend = () => { - if (!list.props.revealOrder) { - // Special case the undefined (falsy) revealOrder, as there - // is no need to coordinate a specific order or unsuspends. - unsuspend(); - } else { - node.push(unsuspend); - resolve(list, child, node); - } - }; - if (delegated) { - delegated(wrappedUnsuspend); - } else { - wrappedUnsuspend(); - } - }; -}; - -SuspenseList.prototype.render = function (props) { - this._next = null; - this._map = new Map(); - - const children = toChildArray(props.children); - if (props.revealOrder && props.revealOrder[0] === 'b') { - // If order === 'backwards' (or, well, anything starting with a 'b') - // then flip the child list around so that the last child will be - // the first in the linked list. - children.reverse(); - } - // Build the linked list. Iterate through the children in reverse order - // so that `_next` points to the first linked list node to be resolved. - for (let i = children.length; i--; ) { - // Create a new linked list node as an array of form: - // [suspended_count, resolved_count, next_node] - // where suspended_count and resolved_count are numeric counters for - // keeping track how many times a node has been suspended and resolved. - // - // Note that suspended_count starts from 1 instead of 0, so we can block - // processing callbacks until componentDidMount has been called. In a sense - // node is suspended at least until componentDidMount gets called! - // - // Pending callbacks are added to the end of the node: - // [suspended_count, resolved_count, next_node, callback_0, callback_1, ...] - this._map.set(children[i], (this._next = [1, 0, this._next])); - } - return props.children; -}; - -SuspenseList.prototype.componentDidUpdate = - SuspenseList.prototype.componentDidMount = function () { - // Iterate through all children after mounting for two reasons: - // 1. As each node[SUSPENDED_COUNT] starts from 1, this iteration increases - // each node[RELEASED_COUNT] by 1, therefore balancing the counters. - // The nodes can now be completely consumed from the linked list. - // 2. Handle nodes that might have gotten resolved between render and - // componentDidMount. - this._map.forEach((node, child) => { - resolve(this, child, node); - }); - };