
<Fragment>
(<>...</>)
<Fragment> 通常使用 <>...</> 代替,它们都允许你在不添加额外节点的情况下将子元素组合。
js
<>
<OneChild />
<AnotherChild />
</>
参考 {/reference/}
<Fragment> {/fragment/}
当你需要单个元素时,你可以使用 <Fragment> 将其他元素组合起来。使用 <Fragment> 组合后的元素不会对 DOM 产生影响,就像元素没有被组合一样。在大多数情况下,<Fragment></Fragment> 可以简写为空的 JSX 元素 <></>。
参数 {/props/}
- 可选
key:列表中<Fragment>可以拥有 keys。 可选 ref:一个 ref 对象(例如来自useRef)或 回调函数。React 提供一个FragmentInstance作为 ref 值,该对象实现了用于与 Fragment 包裹的 DOM 节点进行交互的方法。
FragmentInstance {/fragmentinstance/}
当你向 Fragment 传递 ref 时,React 会提供一个 FragmentInstance 对象,其中包含与 Fragment 包裹的 DOM 节点交互的方法:
事件处理方法:
addEventListener(type, listener, options?):向 Fragment 的所有第一层 DOM 子节点添加事件监听器。removeEventListener(type, listener, options?):从 Fragment 的所有第一层 DOM 子节点移除事件监听器。dispatchEvent(event):向 Fragment 的虚拟子节点派发事件,以调用任何已添加的监听器,并可冒泡到 DOM 父节点。
布局方法:
compareDocumentPosition(otherNode):比较 Fragment 与另一个节点的文档位置。- 如果 Fragment 有子节点,则返回原生的
compareDocumentPosition值。 - 空的 Fragment 将尝试在 React 树内比较位置,并包含
Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC。 - 由于 portal 或其他插入方式而导致在 React 树和 DOM 树中具有不同关系的元素,标记为
Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC。
- 如果 Fragment 有子节点,则返回原生的
getClientRects():返回一个扁平化的DOMRect对象数组,表示所有子元素的边界矩形。getRootNode():返回包含 Fragment 父级 DOM 节点的根节点。
焦点管理方法:
focus(options?):聚焦 Fragment 中第一个可聚焦的 DOM 节点。对嵌套子节点进行深度优先的聚焦尝试。focusLast(options?):聚焦 Fragment 中最后一个可聚焦的 DOM 节点。对嵌套子节点进行深度优先的聚焦尝试。blur():如果document.activeElement在 Fragment 内部,则移除焦点。
观察者方法:
observeUsing(observer):使用 IntersectionObserver 或 ResizeObserver 开始观察 Fragment 的 DOM 子节点。unobserveUsing(observer):使用指定的观察者停止观察 Fragment 的 DOM 子节点。
注意事项 {/caveats/}
-
如果你要传递
key给一个<Fragment>,你不能使用<>...</>,你必须从'react'中导入Fragment,并使用<Fragment key={yourKey}>...</Fragment>的写法。 -
当你要从
<><Child /></>转换为[<Child />],或从<><Child /></>转换为<Child />时,React 并不会重置 state。这个规则只在一层深度的情况下生效,如果从<><><Child /></></>转换为<Child />,则会重置 state。在这里查看更详细的介绍。 -
如果你想向 Fragment 传递 ref,你不能使用<>...</>语法。你必须显式地从'react'中导入Fragment,并渲染<Fragment ref={yourRef}>...</Fragment>。
用法 {/usage/}
返回多个元素 {/returning-multiple-elements/}
使用 Fragment 或简写语法 <>...</> 将多个元素组合在一起,你可以使用它将多个元素等效于单个元素。例如,一个组件只能返回一个元素,但是可以使用 Fragment 将多个元素组合在一起,并作为一个元素返回:
js {3,6}
function Post() {
return (
<>
<PostTitle />
<PostBody />
</>
);
}
Fragment 作用很大,它与将元素包裹在一个 DOM 容器中不同,使用 Fragment 对元素进行组合后不会影响布局和样式。如果你使用浏览器调试工具查看这个示例,你会发现所有的 <h1> 和 <article> DOM 节点都是没有父元素的兄弟节点:
js
export default function Blog() {
return (
<>
<Post title="An update" body="It's been a while since I posted..." />
<Post title="My new blog" body="I am starting a new blog!" />
</>
)
}
function Post({ title, body }) {
return (
<>
<PostTitle title={title} />
<PostBody body={body} />
</>
);
}
function PostTitle({ title }) {
return <h1>{title}</h1>
}
function PostBody({ body }) {
return (
<article>
<p>{body}</p>
</article>
);
}
如何使用完整的语法编写 Fragment? {/how-to-write-a-fragment-without-the-special-syntax/}
下面的示例从 React 中导入了 Fragment:
js {1,5,8}
import { Fragment } from 'react';
function Post() {
return (
<Fragment>
<PostTitle />
<PostBody />
</Fragment>
);
}
通常你不需要这样写,除非你需要将 key 传递给 Fragment。
分配多个元素给一个变量 {/assigning-multiple-elements-to-a-variable/}
和其他元素一样,你可以将 Fragment 元素分配给变量,作为 props 传递等:
js
function CloseDialog() {
const buttons = (
<>
<OKButton />
<CancelButton />
</>
);
return (
<AlertDialog buttons={buttons}>
Are you sure you want to leave this page?
</AlertDialog>
);
}
组合文本与组件 {/grouping-elements-with-text/}
你可以使用 Fragment 将文本与组件组合在一起:
js
function DateRangePicker({ start, end }) {
return (
<>
From
<DatePicker date={start} />
to
<DatePicker date={end} />
</>
);
}
渲染 Fragment 列表 {/rendering-a-list-of-fragments/}
在这种情况下,你需要显式地表示为 Fragment,而不是使用简写语法 <></>。当你在循环中渲染多个元素时,你需要为每一个元素分配一个 key。如果这个元素为 Fragment 时,则需要使用普通的 JSX 语法来提供 key 属性。
js {3,6}
function Blog() {
return posts.map(post =>
<Fragment key={post.id}>
<PostTitle title={post.title} />
<PostBody body={post.body} />
</Fragment>
);
}
你可以查看 DOM 以验证组合后的子元素实际上并没有父元素 Fragment:
js
import { Fragment } from 'react';
const posts = [
{ id: 1, title: 'An update', body: "It's been a while since I posted..." },
{ id: 2, title: 'My new blog', body: 'I am starting a new blog!' }
];
export default function Blog() {
return posts.map(post =>
<Fragment key={post.id}>
<PostTitle title={post.title} />
<PostBody body={post.body} />
</Fragment>
);
}
function PostTitle({ title }) {
return <h1>{title}</h1>
}
function PostBody({ body }) {
return (
<article>
<p>{body}</p>
</article>
);
}
使用 Fragment ref 进行 DOM 交互 {/using-fragment-refs-for-dom-interaction/}
Fragment ref 允许你在不添加额外包裹元素的情况下,与 Fragment 包裹的 DOM 节点进行交互。这对于事件处理、可见性跟踪、焦点管理以及替换像 ReactDOM.findDOMNode() 这样的废弃模式非常有用。
js
import { Fragment } from 'react';
function ClickableFragment({ children, onClick }) {
return (
<Fragment ref={fragmentInstance => {
fragmentInstance.addEventListener('click', handleClick);
return () => fragmentInstance.removeEventListener('click', handleClick);
}}>
{children}
</Fragment>
);
}
使用 Fragment ref 跟踪可见性 {/tracking-visibility-with-fragment-refs/}
Fragment ref 对于可见性跟踪和交叉观察非常有用。这使你能够监控内容何时可见,而无需让子组件暴露 ref:
js {19,21,31-34}
import { Fragment, useRef, useLayoutEffect } from 'react';
function VisibilityObserverFragment({ threshold = 0.5, onVisibilityChange, children }) {
const fragmentRef = useRef(null);
useLayoutEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
onVisibilityChange(entries.some(entry => entry.isIntersecting))
},
{ threshold }
);
fragmentRef.current.observeUsing(observer);
return () => fragmentRef.current.unobserveUsing(observer);
}, [threshold, onVisibilityChange]);
return (
<Fragment ref={fragmentRef}>
{children}
</Fragment>
);
}
function MyComponent() {
const handleVisibilityChange = (isVisible) => {
console.log('Component is', isVisible ? 'visible' : 'hidden');
};
return (
<VisibilityObserverFragment onVisibilityChange={handleVisibilityChange}>
<SomeThirdPartyComponent />
<AnotherComponent />
</VisibilityObserverFragment>
);
}
这种模式是基于 Effect 的可见性日志记录的替代方案,后者在大多数情况下是一种反模式。仅依赖 Effect 并不能保证渲染后的组件对用户是可见的。
使用 Fragment ref 进行焦点管理 {/focus-management-with-fragment-refs/}
Fragment ref 提供了跨 Fragment 内所有 DOM 节点工作的焦点管理方法:
js
import { Fragment, useRef } from 'react';
function FocusFragment({ children }) {
return (
<Fragment ref={(fragmentInstance) => fragmentInstance?.focus()}>
{children}
</Fragment>
);
}
focus() 方法聚焦 Fragment 内第一个可聚焦的元素,而 focusLast() 则聚焦最后一个可聚焦的元素。
帮助我们改进文档
发现翻译问题或内容错误?请告诉我们。
