114 lines
4.0 KiB
JavaScript
114 lines
4.0 KiB
JavaScript
"use strict";
|
|
|
|
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.fastComponent = fastComponent;
|
|
exports.fastComponentRef = fastComponentRef;
|
|
exports.getInstance = getInstance;
|
|
exports.register = register;
|
|
exports.setInstance = setInstance;
|
|
var React = _interopRequireWildcard(require("react"));
|
|
var _useRefWithInit = require("./useRefWithInit");
|
|
const hooks = [];
|
|
let currentInstance = undefined;
|
|
function getInstance() {
|
|
return currentInstance;
|
|
}
|
|
function setInstance(instance) {
|
|
currentInstance = instance;
|
|
}
|
|
function register(hook) {
|
|
hooks.push(hook);
|
|
}
|
|
|
|
/**
|
|
* Wraps a component function to enable performance optimizations for internal hooks.
|
|
*
|
|
* **Performance Optimization:**
|
|
* Components wrapped with `fastComponent` have access to a shared "instance" context that enables
|
|
* specialized hook implementations to batch operations and reduce overhead. The wrapper creates a
|
|
* stable instance object that persists across renders, sets it as the current context, calls
|
|
* registered hooks before and after rendering, then clears the context. The primary benefit is
|
|
* with `useStore`, where multiple store subscriptions within the same component are collapsed into
|
|
* a single `useSyncExternalStore` subscription per store, significantly reducing re-render overhead.
|
|
* This optimization is only active on React 19+; on earlier versions `useStore` falls back to a
|
|
* separate subscription per call.
|
|
*
|
|
* **Requirements:**
|
|
* - The component function should follow standard React component patterns
|
|
* - `useStore` calls must keep a stable order and count across renders, as batched hooks are
|
|
* matched by call index
|
|
* - Do not rely on the instance context outside of specialized hooks
|
|
*
|
|
* @param fn - The component function to wrap
|
|
* @returns A wrapped component with the same signature as the input function
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* // Wrapping a component to enable optimized useStore batching
|
|
* export const TooltipRoot = fastComponent(function TooltipRoot(props) {
|
|
* // These useStore calls share a single subscription
|
|
* const open = useStore(store, (state) => state.open);
|
|
* const disabled = useStore(store, (state) => state.disabled);
|
|
* const value = useStore(store, (state) => state.value);
|
|
* // ...
|
|
* });
|
|
* ```
|
|
*/
|
|
function fastComponent(fn) {
|
|
const FastComponent = (props, forwardedRef) => {
|
|
const instance = (0, _useRefWithInit.useRefWithInit)(createInstance).current;
|
|
let result;
|
|
try {
|
|
currentInstance = instance;
|
|
for (const hook of hooks) {
|
|
hook.before(instance);
|
|
}
|
|
result = fn(props, forwardedRef);
|
|
for (const hook of hooks) {
|
|
hook.after(instance);
|
|
}
|
|
instance.didInitialize = true;
|
|
} finally {
|
|
currentInstance = undefined;
|
|
}
|
|
return result;
|
|
};
|
|
FastComponent.displayName = fn.displayName || fn.name;
|
|
return FastComponent;
|
|
}
|
|
|
|
/**
|
|
* Wraps a component function with ref forwarding to enable performance optimizations for internal hooks.
|
|
*
|
|
* This is a convenience wrapper that combines `fastComponent` with `React.forwardRef`, enabling
|
|
* both performance optimizations and proper ref forwarding. See `fastComponent` for details on
|
|
* the performance benefits.
|
|
*
|
|
* @param fn - The component function that accepts props and a forwarded ref
|
|
* @returns A wrapped component with ref forwarding enabled
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* // Wrapping a component with ref forwarding and optimized hooks
|
|
* export const TooltipTrigger = fastComponentRef(function TooltipTrigger(
|
|
* props,
|
|
* forwardedRef
|
|
* ) {
|
|
* const store = useContext(TooltipContext);
|
|
* const open = useStore(store, (state) => state.open);
|
|
* // ... component logic with ref
|
|
* return <button ref={forwardedRef} {...props} />;
|
|
* });
|
|
* ```
|
|
*/
|
|
function fastComponentRef(fn) {
|
|
return /*#__PURE__*/React.forwardRef(fastComponent(fn));
|
|
}
|
|
function createInstance() {
|
|
return {
|
|
didInitialize: false
|
|
};
|
|
} |