compose 包是一组实用的 Hooks 和 高阶组件 (HOCs),可用于包装你的 WordPress 组件并提供一些基本功能,例如:状态、实例 ID、纯组件等。

compose 函数灵感来源于 Lodash 的 flowRight,其工作方式相同。它源自函数式编程,允许你组合任意数量的函数。你也可以将其理解为函数的分层;compose 会先执行最后一个函数,然后依次向前通过之前的函数,将每个函数的结果向上传递。

以下示例说明了两个函数的组合:

const compose = ( f, g ) => x
    => f( g( x ) );

以下是来自 Gutenberg 的 PluginSidebar 组件 中 compose 使用的简化示例:

使用 compose:

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 );

如果不使用 compose,代码将如下所示:

const applyWithSelect = withSelect( ( select, ownProps ) => {
    return doSomething( select, ownProps );
} );
const applyWithDispatch = withDispatch( ( dispatch, ownProps ) => {
    return doSomethingElse( dispatch, ownProps );
} );

export default withPluginContext(
    applyWithSelect( applyWithDispatch( PluginSidebarMoreMenuItem ) )
);

安装

安装模块

npm install @wordpress/compose --save

本包假设你的代码将在 ES2015+ 环境中运行。如果你使用的是对这类语言特性和 API 支持有限或完全不支持的环境,请在代码中包含 @wordpress/babel-preset-default 随附的 polyfill。

API

更多详细信息,请参阅每个高阶组件的 README 文件。可用组件位于此处。

compose

将多个高阶组件组合成单个高阶组件。执行从右到左的函数组合,每次连续调用都会接收前一次调用的返回值。

这灵感来源于 lodash 的 flowRight 函数。

相关

createHigherOrderComponent

给定一个将组件映射到增强组件及修饰符名称的函数,返回带有生成的 displayName 的增强组件。

参数

  • mapComponent ( Inner: TInner ) => TOuter:将组件映射到增强组件的函数。
  • modifierName string:用于生成显示名称的种子名称。

返回

  • 具有分配生成的 display name 的组件类。

debounce

Lodash 的 debounce 的简化且类型正确的版本,始终使用计时器而不是有时使用 rAF。

创建一个防抖函数,该函数会在距离上次调用防抖函数后经过 wait 毫秒后才调用 func。防抖函数带有一个 cancel 方法用于取消延迟的 func 调用,以及一个 flush 方法用于立即调用它们。提供 options 以指示是否应在 wait 超时的前沿和/或尾部边缘调用 func。func 使用传递给防抖函数的最后一个参数进行调用。后续对防抖函数的调用返回上一次 func 调用的结果。

注意:如果 leading 和 trailing 选项为 true,则仅当在 wait 超时期间防抖函数被调用多次时,func 才会在超时的尾部边缘被调用。

如果 wait 为 0 且 leading 为 false,则 func 调用会被推迟到下一个 tick,类似于超时为 0 的 setTimeout。

参数

  • func Function:要防抖的函数。
  • wait number:要延迟的毫秒数。
  • options Partial< DebounceOptions >:选项对象。
  • options.leading boolean:指定在超时的前沿边缘调用。
  • options.maxWait number:func 在被调用之前允许的最大延迟时间。
  • options.trailing boolean:指定在超时的尾部边缘调用。

返回

  • 返回新的防抖函数。

ifCondition

高阶组件创建器,创建一个新组件,当满足给定条件或使用给定的可选 prop 名称时进行渲染。

用法

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>;

参数

  • predicate ( props: Props ) => boolean:用于测试条件的函数。

返回

  • 高阶组件。

observableMap

ObservableMap 的构造函数(工厂),这是一种类似 map 的键值数据结构,其中各个条目是可观察的:使用 subscribe 方法,你可以订阅特定键的更新。每个订阅者始终观察一个特定的键,并且不会收到 ObservableMap 中任何不相关更改(针对不同的键)的通知。

返回

  • ObservableMap< K, V >:ObservableMap 类型的新实例。

pipe

将多个高阶组件组合成单个高阶组件。执行从左到右的函数组合,每次连续调用都会接收前一次调用的返回值。

这灵感来源于 lodash 的 flow 函数。

相关

privateApis

私有 @wordpress/compose API。

pure

已弃用 请改用 memo 或 PureComponent。

给定一个组件,返回增强后的组件,该组件仅在 props/state 更改时才重新渲染。

throttle

Lodash 的 throttle 的简化且类型正确的版本,始终使用计时器而不是有时使用 rAF。

创建一个节流函数,该函数每隔 wait 毫秒最多调用一次 func。节流函数带有一个 cancel 方法用于取消延迟的 func 调用,以及一个 flush 方法用于立即调用它们。提供 options 以指示是否应在 wait 超时的前沿和/或尾部边缘调用 func。func 使用传递给节流函数的最后一个参数进行调用。后续对节流函数的调用返回上一次 func 调用的结果。

注意:如果 leading 和 trailing 选项为 true,则仅当在 wait 超时期间节流函数被调用多次时,func 才会在超时的尾部边缘被调用。

如果 wait 为 0 且 leading 为 false,则 func 调用会被推迟到下一个 tick,类似于超时为 0 的 setTimeout。

参数

  • func Function:要节流的函数。
  • wait number:节流调用的毫秒数。
  • options Partial< ThrottleOptions >:选项对象。
  • options.leading boolean:指定在超时的前沿边缘调用。
  • options.trailing boolean:指定在超时的尾部边缘调用。

返回

  • 返回新的节流函数。

useAsyncList

React hook 返回一个数组,其项目从源数组异步追加。出于性能原因,如果我们希望异步渲染项目列表,这种行为非常有用。

参数

  • list T[]: 源数组。
  • config AsyncListConfig: 配置对象。

返回

  • T[]: 异步数组。

useConstrainedTabbing

在对话框/模态框中,Tab 键导航必须限制在包装元素的内容范围内。此 Hook 将行为添加到返回的 ref 中。

用法

import { useConstrainedTabbing } from '@wordpress/compose';

const ConstrainedTabbingExample = () => {
    const constrainedTabbingRef = useConstrainedTabbing()
    return (
        <div ref={ constrainedTabbingRef }>
            <Button />
            <Button />
        </div>
    );
}

返回

  • React.RefCallback< Element >: 元素 Ref。

useCopyOnClick

已弃用

当元素被点击时,将文本复制到剪贴板。

参数

  • ref RefObject< string | Element | NodeListOf< Element > | null >: 带有元素的引用。
  • text string | ( () => string ): 要复制的文本。
  • timeout number: 重置返回状态的可选超时时间。默认为 4 秒。

返回

  • boolean: 文本是否已被复制。超时后重置。

useCopyToClipboard

当元素被点击时,将给定文本复制到剪贴板。

参数

  • text string | ( () => string ): 要复制的文本。如果文本尚不可用且计算昂贵,请使用函数。
  • onSuccess () => void: 文本复制成功时调用。

返回

  • RefCallback< T >: 分配给目标元素的 ref。

useDebounce

对函数进行防抖处理,类似于 Lodash 的 debounce。如果任何参数(包括要防抖的函数)发生变化,将返回一个新的防抖函数并取消任何计划的调用,因此请将组件渲染期间创建的函数包装在 useCallback 中。

相关

参数

  • fn TFunc: 要防抖的函数。
  • wait number: 延迟的毫秒数。
  • options DebounceOptions: 选项对象。

返回

  • DebouncedFunc< TFunc >: 防抖函数。

useDebouncedInput

用于需要在输入值之前进行防抖处理的输入字段的辅助 Hook。

参数

  • defaultValue 要使用的默认值。

返回

  • [ string, ( value: string ) => void, string ]: 输入值、设置器和防抖后的输入值。

useDisabled

在某些情况下,例如区块预览,所有可聚焦的 DOM 元素(输入字段、链接、按钮等)都需要禁用。此 Hook 将禁用嵌套 DOM 元素的行为添加到返回的 ref 中。

如果可以,请优先使用 inert HTML 属性。

用法

import { useDisabled } from '@wordpress/compose';

const DisabledExample = () => {
    const disabledRef = useDisabled();
    return (
        <div ref={ disabledRef }>
            <a href="#">此链接的 tabindex 将设置为 -1</a>
            <input
                placeholder="此输入字段将添加 disabled 属性。"
                type="text"
            />
        </div>
    );
};

参数

  • config Object: 配置对象。
  • config.isDisabled boolean=: 元素是否应被禁用。

返回

  • React.RefCallback<HTMLElement>: 元素 Ref。

useEvent

创建一个稳定的回调函数,可以访问最新状态,并可用于事件处理程序和效果回调中。在渲染阶段使用时会抛出异常。

用法

function Component( props ) {
    const onClick = useEvent( props.onClick );
    useEffect( () => {
        onClick();
        // 当 props.onClick 更新时,不会再次触发效果。
    }, [ onClick ] );
    // 当 props.onClick 更新时,Button 不会重新渲染(如果 `Button`
    // 包裹在 `React.memo` 中)。
    return <Button onClick={ onClick } />;
}

参数

  • callback T: 要包装的回调函数。

useFocusableIframe

当 iframe 获得焦点时,派发一个冒泡的 focus 事件。像往常一样在 iframe 或父元素上使用 onFocus。

返回

  • RefCallback< HTMLIFrameElement >: 传递给 iframe 的 Ref。

useFocusOnMount

确定元素挂载时的焦点行为。

用法

import { useFocusOnMount } from '@wordpress/compose';

const WithFocusOnMount = () => {
    const ref = useFocusOnMount();
    return (
        <div ref={ ref }>
            <Button />
            <Button />
        </div>
    );
};

参数

  • focusOnMount useFocusOnMount.Mode: 行为模式。默认为 "firstElement",聚焦于内部第一个可 Tab 的元素;"firstInputElement" 聚焦于内部第一个值控件;true 聚焦于元素本身;false 不执行任何操作。

返回

  • Ref 回调。

useFocusReturn

添加卸载时将焦点返回到先前拥有它的元素的行为,这对于菜单或对话框等角色是预期的。

用法

import { useFocusReturn } from '@wordpress/compose';

const WithFocusReturn = () => {
    const ref = useFocusReturn()
    return (
        <div ref={ ref }>
            <Button />
            <Button />
        </div>
    );
}

参数

  • onFocusReturn () => void: 覆盖默认的返回行为。

返回

  • React.RefCallback< HTMLElement >: 元素 Ref。

useInstanceId

指定 useInstanceId 函数 签名。

更准确地说,useInstanceId 区分三种不同的签名:

  1. 当仅提供 object 时,返回值是一个数字
  2. 当提供 object 和 prefix 时,返回值是一个字符串
  3. 当提供 preferredId 时,返回值是 preferredId 的类型

参数

  • object object: 用于创建 ID 的对象引用。

useIsomorphicLayoutEffect

在支持服务器端渲染组件 (SSR) 时,首选使用此 Hook 而不是直接使用 useLayoutEffect,因为目前 React 在使用 useLayoutEffect 时会发出警告。

useKeyboardShortcut

附加键盘快捷键处理程序。

相关

参数

  • shortcuts string[] | string: 键盘快捷键。
  • callback ( e: ExtendedKeyboardEvent, combo: string ) => void: 快捷键回调。
  • options Partial< KeyboardShortcutConfig >: 快捷键选项。
  • options.bindGlobal Partial< KeyboardShortcutConfig >[ 'bindGlobal' ]:
  • options.eventName Partial< KeyboardShortcutConfig >[ 'eventName' ]:
  • options.isDisabled Partial< KeyboardShortcutConfig >[ 'isDisabled' ]:
  • options.target Partial< KeyboardShortcutConfig >[ 'target' ]:

useMediaQuery

运行媒体查询并在其值变化时返回该值。

参数

  • query [string]: 媒体查询。
  • view [Window | undefined]: Window 实例,否则默认为全局 window

返回

  • boolean: 媒体查询的返回值。

useMergeRefs

将多个 refs 合并为一个 ref 回调。

它还确保合并的 ref 回调仅在它们发生变化时(由于 useCallback 依赖项更新)或当 ref 值发生变化时才被调用,正如 React 在向组件传递单个 ref 回调时所做的事情一样。

正如预期的那样,如果您在每次渲染时都传递一个新函数,ref 回调将在每次渲染后被调用。

如果您不希望 ref 回调在每次渲染后都被调用,请用 useCallback( callback, dependencies ) 将其包装。当依赖项发生变化时,旧的 ref 回调将以 null 调用,新的 ref 回调将以相同的值调用。

内部 ref 回调可以返回一个清理函数(React 19 的 ref 回调清理模式)。当 ref 回调返回一个函数时,该函数将在拆卸阶段(节点更改、依赖项更改或卸载)被调用,而不是以 null 作为参数调用回调。那些不返回清理函数的回调在拆卸时仍会像以前一样接收 null。

还可以通过简单地不传递 ref 来禁用 ref(及其行为)。

const ref = useCallback( ( node ) => {
  node.addEventListener( ... );
  return () => {
    node.removeEventListener( ... );
  };
}, [ ...dependencies ] );
const otherRef = useRef();
const mergedRefs = useMergeRefs( [
  enabled && ref,
  otherRef,
] );
return <div ref={ mergedRefs } />;

参数

  • refs Ref< T >[]: 要合并的 refs。

返回

  • RefCallback< T >: 合并后的 ref 回调。

useObservableValue

允许你观察 ObservableMap 中条目的 React hook。该 hook 返回与键对应的当前值,如果没有存储值则返回 undefined。它还会观察值的变化,并在值发生变化时触发调用组件的更新。

参数

  • map ObservableMap< K, V >: 要观察的 ObservableMap。
  • name K: 要观察的 map 键。

返回

  • V | undefined: 对应于请求的 map 键的值。

usePrevious

获取上一次渲染时的值。基于 https://usehooks.com/usePrevious/。

参数

  • value T: 要跟踪的值。

返回

  • T | undefined: 上一次渲染时的值。

useReducedMotion

返回用户是否偏好减少运动的 hook。

返回

  • boolean: 减少运动偏好值。

useRefEffect

类似 Effect 的 ref 回调。就像使用 useEffect 一样,这允许你返回一个清理函数,以便在 ref 更改或其中一个依赖项更改时运行。ref 将作为参数提供给回调函数。它与 useEffect 的主要区别在于,当 ref 更改时 useEffect 回调不会被调用,但此方法会如此。将返回的 ref 回调作为组件的 ref 传递,并使用 useMergeRefs 合并多个 refs。

值得注意的是,如果依赖项数组为空,严格来说不需要清理事件处理程序(例如),因为节点将被移除。如果你添加了依赖项,则这是必要的,因为 ref 回调将对同一节点多次调用。

参数

  • callback ( node: TElement ) => ( () => void ) | void: 带有 ref 作为参数的回调。
  • dependencies DependencyList: 回调的依赖项。

返回

  • RefCallback< TElement | null >: Ref 回调。

useResizeObserver

为 HTML 或 SVG 元素设置 ResizeObserver。

将返回的设置器作为回调 ref 传递给你要观察的 React 元素,或者在布局 effect 中使用它以应对高级用例。

用法

const setElement = useResizeObserver(
    ( resizeObserverEntries ) => console.log( resizeObserverEntries ),
    { box: 'border-box' }
);
<div ref={ setElement } />;

// 设置器还可以以其他方式使用,例如:
useLayoutEffect( () => {
    setElement( document.querySelector( `data-element-id="${ elementId }"` ) );
}, [ elementId ] );

参数

  • callback ResizeObserverCallback: ResizeObserver 回调 – MDN 文档。
  • options ResizeObserverOptions: 调用时传递给 ResizeObserver.observe 的选项 – MDN 文档。更改将被忽略。

useStateWithHistory

具有撤销/重做历史的 useState。

参数

  • initialValue T: 初始值。

返回

  • Value, setValue, hasUndo, hasRedo, undo, redo。

useThrottle

对函数进行节流,类似于 Lodash 的 throttle。如果任何参数(包括要节流的函数)发生更改,将返回一个新的节流函数并取消任何已调度的调用,因此请将渲染期间创建的函数包装在组件的 useCallback 中。

相关

参数

  • fn TFunc: 要节流的函数。
  • wait number: 节流调用的毫秒数。
  • options ThrottleOptions: 选项对象。

返回

  • DebouncedFunc< TFunc >: 节流后的函数。

useViewportMatch

如果视口匹配给定的查询,则返回 true,否则返回 false。

用法

useViewportMatch( 'huge', '<' );
useViewportMatch( 'medium' );

参数

  • breakpoint Breakpoint: 断点大小名称。
  • operator ViewportOperator: 视口运算符。
  • view Window | undefined: 在其中执行视口匹配的 Window 实例。

返回

  • boolean: 视口是否匹配查询。

useWarnOnChange

执行对象新值与旧值之间浅比较的 hook,如果有差异,则将其打印到控制台。这在性能相关工作中很有用,用于检查组件重新渲染的原因。

用法

function MyComponent( props: Record< string, any > ) {
    useWarnOnChange( props );

    return 'Something';
}

参数

  • object Record< string, any > | any[]: 要比较更改的对象。
  • prefix string: 仅在控制台日志显示时的前缀。

withGlobalEvents

已弃用

高阶组件创建器,给定一个 DOM 事件类型和值的对象,这些值对应于组件上回调函数的名称,它将创建或更新一个窗口事件处理程序,以便在事件发生时调用回调。代表消费开发者,高阶组件管理组件卸载时的解绑,并为整个应用程序绑定最多单个事件处理程序。

参数

  • eventTypesToHandlers Record<keyof GlobalEventHandlersEventMap, string>: 键为 DOM 事件类型的对象,值为原始组件实例上处理该事件的函数名称。

返回

  • any: 高阶组件。

withInstanceId

用于按组件提供唯一实例 ID 的高阶组件。

withSafeTimeout

用于提供和管理应绑定到组件生命周期的延迟函数调用的高阶组件。

withState

已弃用 请改用 useState。

用于通过 props 提供和管理组件内部状态的高阶组件。

参数

  • initialState any: 组件的可选初始状态。

返回

  • any: 接受一个组件的高阶组件包装器,该组件接受 state props + 其自身的 props + setState,并返回一个仅接受自身 props 的组件。

贡献到此包

这是 Gutenberg 项目的一个独立包。该项目组织为一个 monorepo。它由多个自包含的软件包组成,每个包都有特定的用途。此 monorepo 中的包发布到 npm,并被 WordPress 以及其他软件项目使用。

要了解有关为此包或整个 Gutenberg 做出贡献的更多信息,请阅读项目的主 贡献者指南。