@wordpress/compose
Version:
WordPress higher-order components (HOCs).
664 lines (403 loc) • 22.5 kB
Markdown
# Compose
The `compose` package is a collection of handy [Hooks](https://react.dev/reference/react/hooks) and [Higher Order Components](https://legacy.reactjs.org/docs/higher-order-components.html) (HOCs) you can use to wrap your WordPress components and provide some basic features like: state, instance id, pure...
The `compose` function is inspired by [flowRight](https://lodash.com/docs/#flowRight) from Lodash and works the same way. It comes from functional programming, and allows you to compose any number of functions. You might also think of this as layering functions; `compose` will execute the last function first, then sequentially move back through the previous functions passing the result of each function upward.
An example that illustrates it for two functions:
```js
const compose = ( f, g ) => x
=> f( g( x ) );
```
Here's a simplified example of **compose** in use from Gutenberg's [`PluginSidebar` component](https://github.com/WordPress/gutenberg/blob/HEAD/packages/editor/src/components/plugin-sidebar/index.js):
Using compose:
```js
const applyWithSelect = withSelect( ( select, ownProps ) => {
return doSomething( select, ownProps );
} );
const applyWithDispatch = withDispatch( ( dispatch, ownProps ) => {
return doSomethingElse( dispatch, ownProps );
} );
export default compose(
withPluginContext,
applyWithSelect,
applyWithDispatch
)( PluginSidebarMoreMenuItem );
```
Without `compose`, the code would look like this:
```js
const applyWithSelect = withSelect( ( select, ownProps ) => {
return doSomething( select, ownProps );
} );
const applyWithDispatch = withDispatch( ( dispatch, ownProps ) => {
return doSomethingElse( dispatch, ownProps );
} );
export default withPluginContext(
applyWithSelect( applyWithDispatch( PluginSidebarMoreMenuItem ) )
);
```
## Installation
Install the module
```bash
npm install @wordpress/compose --save
```
_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for such language features and APIs, you should include [the polyfill shipped in `@wordpress/babel-preset-default`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/babel-preset-default#polyfill) in your code._
## API
For more details, you can refer to each Higher Order Component's README file. [Available components are located here.](https://github.com/WordPress/gutenberg/tree/HEAD/packages/compose/src)
<!-- START TOKEN(Autogenerated API docs) -->
### compose
Composes multiple higher-order components into a single higher-order component. Performs right-to-left function composition, where each successive invocation is supplied the return value of the previous.
This is inspired by `lodash`'s `flowRight` function.
_Related_
- <https://lodash.com/docs/4#flow-right>
### createHigherOrderComponent
Given a function mapping a component to an enhanced component and modifier name, returns the enhanced component augmented with a generated displayName.
_Parameters_
- _mapComponent_ `( Inner: TInner ) => TOuter`: Function mapping component to enhanced component.
- _modifierName_ `string`: Seed name from which to generated display name.
_Returns_
- Component class with generated display name assigned.
### debounce
A simplified and properly typed version of lodash's `debounce`, that always uses timers instead of sometimes using rAF.
Creates a debounced function that delays invoking `func` until after `wait` milliseconds have elapsed since the last time the debounced function was invoked. The debounced function comes with a `cancel` method to cancel delayed `func` invocations and a `flush` method to immediately invoke them. Provide `options` to indicate whether `func` should be invoked on the leading and/or trailing edge of the `wait` timeout. The `func` is invoked with the last arguments provided to the debounced function. Subsequent calls to the debounced function return the result of the last `func` invocation.
**Note:** If `leading` and `trailing` options are `true`, `func` is invoked on the trailing edge of the timeout only if the debounced function is invoked more than once during the `wait` timeout.
If `wait` is `0` and `leading` is `false`, `func` invocation is deferred until the next tick, similar to `setTimeout` with a timeout of `0`.
_Parameters_
- _func_ `Function`: The function to debounce.
- _wait_ `number`: The number of milliseconds to delay.
- _options_ `Partial< DebounceOptions >`: The options object.
- _options.leading_ `boolean`: Specify invoking on the leading edge of the timeout.
- _options.maxWait_ `number`: The maximum time `func` is allowed to be delayed before it's invoked.
- _options.trailing_ `boolean`: Specify invoking on the trailing edge of the timeout.
_Returns_
- Returns the new debounced function.
### ifCondition
Higher-order component creator, creating a new component which renders if the given condition is satisfied or with the given optional prop name.
_Usage_
```ts
type Props = { foo: string };
const Component = ( props: Props ) => <div>{ props.foo }</div>;
const ConditionalComponent = ifCondition( ( props: Props ) => props.foo.length !== 0 )( Component );
<ConditionalComponent foo="" />; // => null
<ConditionalComponent foo="bar" />; // => <div>bar</div>;
```
_Parameters_
- _predicate_ `( props: Props ) => boolean`: Function to test condition.
_Returns_
- Higher-order component.
### observableMap
A constructor (factory) for `ObservableMap`, a map-like key/value data structure where the individual entries are observable: using the `subscribe` method, you can subscribe to updates for a particular keys. Each subscriber always observes one specific key and is not notified about any unrelated changes (for different keys) in the `ObservableMap`.
_Returns_
- `ObservableMap< K, V >`: A new instance of the `ObservableMap` type.
### pipe
Composes multiple higher-order components into a single higher-order component. Performs left-to-right function composition, where each successive invocation is supplied the return value of the previous.
This is inspired by `lodash`'s `flow` function.
_Related_
- <https://lodash.com/docs/4#flow>
### pure
> **Deprecated** Use `memo` or `PureComponent` instead.
Given a component returns the enhanced component augmented with a component only re-rendering when its props/state change
### throttle
A simplified and properly typed version of lodash's `throttle`, that always uses timers instead of sometimes using rAF.
Creates a throttled function that only invokes `func` at most once per every `wait` milliseconds. The throttled function comes with a `cancel` method to cancel delayed `func` invocations and a `flush` method to immediately invoke them. Provide `options` to indicate whether `func` should be invoked on the leading and/or trailing edge of the `wait` timeout. The `func` is invoked with the last arguments provided to the throttled function. Subsequent calls to the throttled function return the result of the last `func` invocation.
**Note:** If `leading` and `trailing` options are `true`, `func` is invoked on the trailing edge of the timeout only if the throttled function is invoked more than once during the `wait` timeout.
If `wait` is `0` and `leading` is `false`, `func` invocation is deferred until the next tick, similar to `setTimeout` with a timeout of `0`.
_Parameters_
- _func_ `Function`: The function to throttle.
- _wait_ `number`: The number of milliseconds to throttle invocations to.
- _options_ `Partial< ThrottleOptions >`: The options object.
- _options.leading_ `boolean`: Specify invoking on the leading edge of the timeout.
- _options.trailing_ `boolean`: Specify invoking on the trailing edge of the timeout.
_Returns_
- Returns the new throttled function.
### useAsyncList
React hook returns an array which items get asynchronously appended from a source array. This behavior is useful if we want to render a list of items asynchronously for performance reasons.
_Parameters_
- _list_ `T[]`: Source array.
- _config_ `AsyncListConfig`: Configuration object.
_Returns_
- `T[]`: Async array.
### useConstrainedTabbing
In Dialogs/modals, the tabbing must be constrained to the content of the wrapper element. This hook adds the behavior to the returned ref.
_Usage_
```js
import { useConstrainedTabbing } from '@wordpress/compose';
const ConstrainedTabbingExample = () => {
const constrainedTabbingRef = useConstrainedTabbing();
return (
<div ref={ constrainedTabbingRef }>
<Button />
<Button />
</div>
);
};
```
_Returns_
- `import('react').RefCallback<Element>`: Element Ref.
### useCopyOnClick
> **Deprecated**
Copies the text to the clipboard when the element is clicked.
_Parameters_
- _ref_ `import('react').RefObject<string | Element | NodeListOf<Element>>`: Reference with the element.
- _text_ `string|Function`: The text to copy.
- _timeout_ `[number]`: Optional timeout to reset the returned state. 4 seconds by default.
_Returns_
- `boolean`: Whether or not the text has been copied. Resets after the timeout.
### useCopyToClipboard
Copies the given text to the clipboard when the element is clicked.
_Parameters_
- _text_ `string | (() => string)`: The text to copy. Use a function if not already available and expensive to compute.
- _onSuccess_ `Function`: Called when to text is copied.
_Returns_
- `import('react').Ref<TElementType>`: A ref to assign to the target element.
### useDebounce
Debounces a function similar to Lodash's `debounce`. A new debounced function will be returned and any scheduled calls cancelled if any of the arguments change, including the function to debounce, so please wrap functions created on render in components in `useCallback`.
_Related_
- <https://lodash.com/docs/4#debounce>
_Parameters_
- _fn_ `TFunc`: The function to debounce.
- _wait_ `[number]`: The number of milliseconds to delay.
- _options_ `[import('../../utils/debounce').DebounceOptions]`: The options object.
_Returns_
- `import('../../utils/debounce').DebouncedFunc<TFunc>`: Debounced function.
### useDebouncedInput
Helper hook for input fields that need to debounce the value before using it.
_Parameters_
- _defaultValue_ The default value to use.
_Returns_
- `[ string, ( value: string ) => void, string ]`: The input value, the setter and the debounced input value.
### useDisabled
In some circumstances, such as block previews, all focusable DOM elements (input fields, links, buttons, etc.) need to be disabled. This hook adds the behavior to disable nested DOM elements to the returned ref.
If you can, prefer the use of the inert HTML attribute.
_Usage_
```js
import { useDisabled } from '@wordpress/compose';
const DisabledExample = () => {
const disabledRef = useDisabled();
return (
<div ref={ disabledRef }>
<a href="#">This link will have tabindex set to -1</a>
<input
placeholder="This input will have the disabled attribute added to it."
type="text"
/>
</div>
);
};
```
_Parameters_
- _config_ `Object`: Configuration object.
- _config.isDisabled_ `boolean=`: Whether the element should be disabled.
_Returns_
- `import('react').RefCallback<HTMLElement>`: Element Ref.
### useEvent
Creates a stable callback function that has access to the latest state and can be used within event handlers and effect callbacks. Throws when used in the render phase.
_Usage_
```tsx
function Component( props ) {
const onClick = useEvent( props.onClick );
useEffect( () => {
onClick();
// Won't trigger the effect again when props.onClick is updated.
}, [ onClick ] );
// Won't re-render Button when props.onClick is updated (if `Button` is
// wrapped in `React.memo`).
return <Button onClick={ onClick } />;
}
```
_Parameters_
- _callback_ `T`: The callback function to wrap.
### useFocusableIframe
Dispatches a bubbling focus event when the iframe receives focus. Use `onFocus` as usual on the iframe or a parent element.
_Returns_
- `RefCallback< HTMLIFrameElement >`: Ref to pass to the iframe.
### useFocusOnMount
Hook used to focus the first tabbable element on mount.
_Usage_
```js
import { useFocusOnMount } from '@wordpress/compose';
const WithFocusOnMount = () => {
const ref = useFocusOnMount();
return (
<div ref={ ref }>
<Button />
<Button />
</div>
);
};
```
_Parameters_
- _focusOnMount_ `boolean | 'firstElement'`: Focus on mount mode.
_Returns_
- `import('react').RefCallback<HTMLElement>`: Ref callback.
### useFocusReturn
Adds the unmount behavior of returning focus to the element which had it previously as is expected for roles like menus or dialogs.
_Usage_
```js
import { useFocusReturn } from '@wordpress/compose';
const WithFocusReturn = () => {
const ref = useFocusReturn();
return (
<div ref={ ref }>
<Button />
<Button />
</div>
);
};
```
_Parameters_
- _onFocusReturn_ `[() => void]`: Overrides the default return behavior.
_Returns_
- `import('react').RefCallback<HTMLElement>`: Element Ref.
### useInstanceId
Provides a unique instance ID.
_Parameters_
- _object_ `object`: Object reference to create an id for.
- _prefix_ `[string]`: Prefix for the unique id.
- _preferredId_ `[string | number]`: Default ID to use.
_Returns_
- `string | number`: The unique instance id.
### useIsomorphicLayoutEffect
Preferred over direct usage of `useLayoutEffect` when supporting server rendered components (SSR) because currently React throws a warning when using useLayoutEffect in that environment.
### useKeyboardShortcut
Attach a keyboard shortcut handler.
_Related_
- <https://craig.is/killing/mice#api.bind> for information about the `callback` parameter.
_Parameters_
- _shortcuts_ `string[]|string`: Keyboard Shortcuts.
- _callback_ `(e: import('mousetrap').ExtendedKeyboardEvent, combo: string) => void`: Shortcut callback.
- _options_ `WPKeyboardShortcutConfig`: Shortcut options.
### useMediaQuery
Runs a media query and returns its value when it changes.
_Parameters_
- _query_ `[string]`: Media Query.
_Returns_
- `boolean`: return value of the media query.
### useMergeRefs
Merges refs into one ref callback.
It also ensures that the merged ref callbacks are only called when they change (as a result of a `useCallback` dependency update) OR when the ref value changes, just as React does when passing a single ref callback to the component.
As expected, if you pass a new function on every render, the ref callback will be called after every render.
If you don't wish a ref callback to be called after every render, wrap it with `useCallback( callback, dependencies )`. When a dependency changes, the old ref callback will be called with `null` and the new ref callback will be called with the same value.
To make ref callbacks easier to use, you can also pass the result of `useRefEffect`, which makes cleanup easier by allowing you to return a cleanup function instead of handling `null`.
It's also possible to _disable_ a ref (and its behaviour) by simply not passing the ref.
```jsx
const ref = useRefEffect( ( node ) => {
node.addEventListener( ... );
return () => {
node.removeEventListener( ... );
};
}, [ ...dependencies ] );
const otherRef = useRef();
const mergedRefs useMergeRefs( [
enabled && ref,
otherRef,
] );
return <div ref={ mergedRefs } />;
```
_Parameters_
- _refs_ `Array<TRef>`: The refs to be merged.
_Returns_
- `import('react').RefCallback<TypeFromRef<TRef>>`: The merged ref callback.
### useObservableValue
React hook that lets you observe an entry in an `ObservableMap`. The hook returns the current value corresponding to the key, or `undefined` when there is no value stored. It also observes changes to the value and triggers an update of the calling component in case the value changes.
_Parameters_
- _map_ `ObservableMap< K, V >`: The `ObservableMap` to observe.
- _name_ `K`: The map key to observe.
_Returns_
- `V | undefined`: The value corresponding to the map key requested.
### usePrevious
Use something's value from the previous render. Based on <https://usehooks.com/usePrevious/>.
_Parameters_
- _value_ `T`: The value to track.
_Returns_
- `T | undefined`: The value from the previous render.
### useReducedMotion
Hook returning whether the user has a preference for reduced motion.
_Returns_
- `boolean`: Reduced motion preference value.
### useRefEffect
Effect-like ref callback. Just like with `useEffect`, this allows you to return a cleanup function to be run if the ref changes or one of the dependencies changes. The ref is provided as an argument to the callback functions. The main difference between this and `useEffect` is that the `useEffect` callback is not called when the ref changes, but this is. Pass the returned ref callback as the component's ref and merge multiple refs with `useMergeRefs`.
It's worth noting that if the dependencies array is empty, there's not strictly a need to clean up event handlers for example, because the node is to be removed. It _is_ necessary if you add dependencies because the ref callback will be called multiple times for the same node.
_Parameters_
- _callback_ `( node: TElement ) => ( () => void ) | void`: Callback with ref as argument.
- _dependencies_ `DependencyList`: Dependencies of the callback.
_Returns_
- `RefCallback< TElement | null >`: Ref callback.
### useResizeObserver
Sets up a [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/Resize_Observer_API) for an HTML or SVG element.
Pass the returned setter as a callback ref to the React element you want to observe, or use it in layout effects for advanced use cases.
_Usage_
```tsx
const setElement = useResizeObserver(
( resizeObserverEntries ) => console.log( resizeObserverEntries ),
{ box: 'border-box' }
);
<div ref={ setElement } />;
// The setter can be used in other ways, for example:
useLayoutEffect( () => {
setElement( document.querySelector( `data-element-id="${ elementId }"` ) );
}, [ elementId ] );
```
_Parameters_
- _callback_ `ResizeObserverCallback`: The `ResizeObserver` callback - [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/ResizeObserver#callback).
- _options_ `ResizeObserverOptions`: Options passed to `ResizeObserver.observe` when called - [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/observe#options). Changes will be ignored.
### useStateWithHistory
useState with undo/redo history.
_Parameters_
- _initialValue_ `T`: Initial value.
_Returns_
- Value, setValue, hasUndo, hasRedo, undo, redo.
### useThrottle
Throttles a function similar to Lodash's `throttle`. A new throttled function will be returned and any scheduled calls cancelled if any of the arguments change, including the function to throttle, so please wrap functions created on render in components in `useCallback`.
_Related_
- <https://lodash.com/docs/4#throttle>
_Parameters_
- _fn_ `TFunc`: The function to throttle.
- _wait_ `[number]`: The number of milliseconds to throttle invocations to.
- _options_ `[import('../../utils/throttle').ThrottleOptions]`: The options object. See linked documentation for details.
_Returns_
- `import('../../utils/debounce').DebouncedFunc<TFunc>`: Throttled function.
### useViewportMatch
Returns true if the viewport matches the given query, or false otherwise.
_Usage_
```js
useViewportMatch( 'huge', '<' );
useViewportMatch( 'medium' );
```
_Parameters_
- _breakpoint_ `WPBreakpoint`: Breakpoint size name.
- _operator_ `[WPViewportOperator]`: Viewport operator.
_Returns_
- `boolean`: Whether viewport matches query.
### useWarnOnChange
Hook that performs a shallow comparison between the preview value of an object and the new one, if there's a difference, it prints it to the console. this is useful in performance related work, to check why a component re-renders.
_Usage_
```jsx
function MyComponent( props ) {
useWarnOnChange( props );
return 'Something';
}
```
_Parameters_
- _object_ `object`: Object which changes to compare.
- _prefix_ `string`: Just a prefix to show when console logging.
### withGlobalEvents
> **Deprecated**
Higher-order component creator which, given an object of DOM event types and values corresponding to a callback function name on the component, will create or update a window event handler to invoke the callback when an event occurs. On behalf of the consuming developer, the higher-order component manages unbinding when the component unmounts, and binding at most a single event handler for the entire application.
_Parameters_
- _eventTypesToHandlers_ `Record<keyof GlobalEventHandlersEventMap, string>`: Object with keys of DOM event type, the value a name of the function on the original component's instance which handles the event.
_Returns_
- `any`: Higher-order component.
### withInstanceId
A Higher Order Component used to provide a unique instance ID by component.
### withSafeTimeout
A higher-order component used to provide and manage delayed function calls that ought to be bound to a component's lifecycle.
### withState
> **Deprecated** Use `useState` instead.
A Higher Order Component used to provide and manage internal component state via props.
_Parameters_
- _initialState_ `any`: Optional initial state of the component.
_Returns_
- `any`: A higher order component wrapper accepting a component that takes the state props + its own props + `setState` and returning a component that only accepts the own props.
<!-- END TOKEN(Autogenerated API docs) -->
## Contributing to this package
This is an individual package that's part of the Gutenberg project. The project is organized as a monorepo. It's made up of multiple self-contained software packages, each with a specific purpose. The packages in this monorepo are published to [npm](https://www.npmjs.com/) and used by [WordPress](https://make.wordpress.org/core/) as well as other software projects.
To find out more about contributing to this package or Gutenberg as a whole, please read the project's main [contributor guide](https://github.com/WordPress/gutenberg/tree/HEAD/CONTRIBUTING.md).
<br /><br /><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p>