<Fragment>๋Š” <>...</> ๋ฌธ๋ฒ•์œผ๋กœ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋ฉฐ, ๋ž˜ํผ ๋…ธ๋“œ ์—†์ด ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๊ทธ๋ฃนํ™”ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

Canary

Fragment๋Š” ref๋ฅผ ๋ฐ›์„ ์ˆ˜๋„ ์žˆ์œผ๋ฉฐ, ๋ž˜ํผ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ ๋„ ๊ธฐ๋ณธ DOM ๋…ธ๋“œ์™€ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ๋ ˆํผ๋Ÿฐ์Šค์™€ ์‚ฌ์šฉ๋ฒ•์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.
<>
<OneChild />
<AnotherChild />
</>

๋ ˆํผ๋Ÿฐ์Šค

<Fragment>

ํ•˜๋‚˜์˜ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ํ•„์š”ํ•œ ์ƒํ™ฉ์—์„œ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ <Fragment>๋กœ ๊ฐ์‹ธ์„œ ๊ทธ๋ฃนํ™”ํ•˜์„ธ์š”. Fragment ์•ˆ์—์„œ ๊ทธ๋ฃนํ™”๋œ ์—˜๋ฆฌ๋จผํŠธ๋Š” DOM ๊ฒฐ๊ณผ๋ฌผ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ๊ทธ๋ฃนํ™”๋˜์ง€ ์•Š์€ ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๋นˆ JSX ํƒœ๊ทธ์ธ <></>๋Š” <Fragment></Fragment>์˜ ์ถ•์•ฝํ˜•์ž…๋‹ˆ๋‹ค.

Props

  • optional key: ๋ช…์‹œ์  <Fragment>๋กœ ์„ ์–ธ๋œ Fragment์—๋Š” key๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Canary only optional ref: ref ๊ฐ์ฒด(์˜ˆ: useRef์—์„œ ๋ฐ˜ํ™˜๋œ ๊ฒƒ) ๋˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. React๋Š” Fragment๋กœ ๊ฐ์‹ผ DOM ๋…ธ๋“œ์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•œ FragmentInstance๋ฅผ ref ๊ฐ’์œผ๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Canary only FragmentInstance

Fragment์— ref๋ฅผ ์ „๋‹ฌํ•˜๋ฉด, React๋Š” Fragment๋กœ ๊ฐ์‹ผ DOM ๋…ธ๋“œ์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ํฌํ•จ๋œ FragmentInstance ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ

  • 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์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
    • ํฌํƒˆ์ด๋‚˜ ๋‹ค๋ฅธ ์‚ฝ์ž…์œผ๋กœ ์ธํ•ด React ํŠธ๋ฆฌ์™€ DOM ํŠธ๋ฆฌ์—์„œ ๋‹ค๋ฅธ ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„ ์—˜๋ฆฌ๋จผํŠธ๋Š” Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC์ž…๋‹ˆ๋‹ค.
  • 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 ์ž์‹ ๊ด€์ฐฐ์„ ์ค‘์ง€ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜ ์‚ฌํ•ญ

  • Fragment์— key๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด <>...</> ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ช…์‹œ์ ์œผ๋กœ react์—์„œ Fragment๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ Import <Fragment key={yourKey}>...</Fragment>๋ฅผ ๋ Œ๋”๋งํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • React๋Š” <><Child /></>์—์„œ [<Child />]๋กœ ๋ Œ๋”๋งํ•˜๊ฑฐ๋‚˜ (๋˜๋Š” ๋ฐ˜๋Œ€์˜ ๊ฒฝ์šฐ), ํ˜น์€ <><Child /></> ์—์„œ <Child /> ๋ Œ๋”๋งํ•˜๊ฑฐ๋‚˜ (๋˜๋Š” ๋ฐ˜๋Œ€์˜ ๊ฒฝ์šฐ) State๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์˜ค์ง ํ•œ ๋‹จ๊ณ„ ๊นŠ์ดSingle Level Deep๊นŒ์ง€๋งŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด <><><Child /></></> ์—์„œ <Child />๋กœ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์€ State๊ฐ€ ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค. ์ •ํ™•ํ•œ ์˜๋ฏธ๋Š” ์—ฌ๊ธฐ์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Canary only Fragment์— ref๋ฅผ ์ „๋‹ฌํ•˜๋ ค๋ฉด <>...</> ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ช…์‹œ์ ์œผ๋กœ 'react'์—์„œ Fragment๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ  <Fragment ref={yourRef}>...</Fragment>๋ฅผ ๋ Œ๋”๋งํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


์‚ฌ์šฉ๋ฒ•

์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ ๋ฐ˜ํ™˜ํ•˜๊ธฐ

์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ํ•จ๊ป˜ ๊ทธ๋ฃนํ™”ํ•˜๊ธฐ ์œ„ํ•ด Fragment๋‚˜ <>...</> ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜์„ธ์š”. ํ•œ ๊ฐœ์˜ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ณณ์— ์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ปดํฌ๋„ŒํŠธ๋Š” ํ•œ ๊ฐœ์˜ ์—˜๋ฆฌ๋จผํŠธ๋งŒ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ Fragment๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ํ•จ๊ป˜ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function Post() {
return (
<>
<PostTitle />
<PostBody />
</>
);
}

Fragment๋กœ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๊ทธ๋ฃนํ™”ํ•˜๋ฉด DOM ์—˜๋ฆฌ๋จผํŠธ์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ์ปจํ…Œ์ด๋„ˆ๋กœ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๊ฐ์‹ธ๋Š” ๊ฒฝ์šฐ์™€๋Š” ๋‹ฌ๋ฆฌ, ๋ ˆ์ด์•„์›ƒ์ด๋‚˜ ์Šคํƒ€์ผ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— Fragment๋Š” ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋กœ ์•„๋ž˜ ์˜ˆ์‹œ๋ฅผ ๊ฒ€์‚ฌํ•˜๋ฉด ๋ชจ๋“  <h1>, <article> DOM ๋…ธ๋“œ๊ฐ€ ๋ž˜ํผ ์—†์ด ํ˜•์ œ ๋…ธ๋“œ๋กœ ๋‚˜ํƒ€๋‚˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ธ๊ฐ€์š”?

์œ„์˜ ์˜ˆ์‹œ๋Š” React์—์„œ Fragment๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š”Import ๊ฒƒ๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

import { Fragment } from 'react';

function Post() {
return (
<Fragment>
<PostTitle />
<PostBody />
</Fragment>
);
}

์ผ๋ฐ˜์ ์œผ๋กœ Fragment์— key๋ฅผ ๋„˜๊ฒจ์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์ด ๊ธฐ๋Šฅ์€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


๋ณ€์ˆ˜์— ์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ ํ• ๋‹น

๋‹ค๋ฅธ ์—˜๋ฆฌ๋จผํŠธ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Fragment๋ฅผ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•˜๊ณ  Props๋กœ ์ „๋‹ฌํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function CloseDialog() {
const buttons = (
<>
<OKButton />
<CancelButton />
</>
);
return (
<AlertDialog buttons={buttons}>
Are you sure you want to leave this page?
</AlertDialog>
);
}

ํ…์ŠคํŠธ์™€ ํ•จ๊ป˜ ์—˜๋ฆฌ๋จผํŠธ ๊ทธ๋ฃนํ™”

Fragment๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…์ŠคํŠธ๋ฅผ ์ปดํฌ๋„ŒํŠธ์™€ ํ•จ๊ป˜ ๊ทธ๋ฃนํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function DateRangePicker({ start, end }) {
return (
<>
From
<DatePicker date={start} />
to
<DatePicker date={end} />
</>
);
}

Fragment ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง

<></> ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  ๋ช…์‹œ์ ์œผ๋กœ Fragment๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ณต์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ ๊ฐ ์š”์†Œ์— key๋ฅผ ํ• ๋‹นํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ณต ์•ˆ์— ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ Fragment์ธ ๊ฒฝ์šฐ key ์†์„ฑ์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ์ผ๋ฐ˜ JSX ์—˜๋ฆฌ๋จผํŠธ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

function Blog() {
return posts.map(post =>
<Fragment key={post.id}>
<PostTitle title={post.title} />
<PostBody body={post.body} />
</Fragment>
);
}

DOM์„ ๊ฒ€์‚ฌํ•˜์—ฌ Fragment ์ž์‹ ์ฃผ์œ„์— ๋ž˜ํผ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์—†๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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


Canary only Fragment ref๋ฅผ ์‚ฌ์šฉํ•œ DOM ์ƒํ˜ธ์ž‘์šฉ

Fragment ref๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ž˜ํผ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ ๋„ Fragment๋กœ ๊ฐ์‹ผ DOM ๋…ธ๋“œ์™€ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ, ๊ฐ€์‹œ์„ฑ ์ถ”์ , ํฌ์ปค์Šค ๊ด€๋ฆฌ, ๊ทธ๋ฆฌ๊ณ  ReactDOM.findDOMNode()์™€ ๊ฐ™์ด ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ํŒจํ„ด์„ ๋Œ€์ฒดํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

import { Fragment } from 'react';

function ClickableFragment({ children, onClick }) {
return (
<Fragment ref={fragmentInstance => {
fragmentInstance.addEventListener('click', handleClick);
return () => fragmentInstance.removeEventListener('click', handleClick);
}}>
{children}
</Fragment>
);
}

Canary only Fragment ref๋กœ ๊ฐ€์‹œ์„ฑ ์ถ”์ ํ•˜๊ธฐ

Fragment ref๋Š” ๊ฐ€์‹œ์„ฑ ์ถ”์ ๊ณผ ๊ต์ฐจ ๊ด€์ฐฐ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ž์‹ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ref๋ฅผ ๋…ธ์ถœํ•˜์ง€ ์•Š์•„๋„ ์ฝ˜ํ…์ธ ๊ฐ€ ํ™”๋ฉด์— ๋ณด์ด๋Š” ์‹œ์ ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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 ๊ธฐ๋ฐ˜ ๋ฐฉ์‹์€ ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์•ˆํ‹ฐํŒจํ„ด์ž…๋‹ˆ๋‹ค. Effect์—๋งŒ ์˜์กดํ•˜๋ฉด ๋ Œ๋”๋ง๋œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ์‹ค์ œ๋กœ ๋ณด์ด๋Š”์ง€ ๋ณด์žฅํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.


Canary only Fragment ref๋กœ ํฌ์ปค์Šค ๊ด€๋ฆฌํ•˜๊ธฐ

Fragment ref๋Š” Fragment ๋‚ด์˜ ๋ชจ๋“  DOM ๋…ธ๋“œ์—์„œ ๋™์ž‘ํ•˜๋Š” ํฌ์ปค์Šค ๊ด€๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

import { Fragment, useRef } from 'react';

function FocusFragment({ children }) {
return (
<Fragment ref={(fragmentInstance) => fragmentInstance?.focus()}>
{children}
</Fragment>
);
}

focus() ๋ฉ”์„œ๋“œ๋Š” Fragment ๋‚ด์˜ ์ฒซ ๋ฒˆ์งธ ํฌ์ปค์Šค ๊ฐ€๋Šฅํ•œ ์—˜๋ฆฌ๋จผํŠธ์— ํฌ์ปค์Šคํ•˜๊ณ , focusLast()๋Š” ๋งˆ์ง€๋ง‰ ํฌ์ปค์Šค ๊ฐ€๋Šฅํ•œ ์—˜๋ฆฌ๋จผํŠธ์— ํฌ์ปค์Šคํ•ฉ๋‹ˆ๋‹ค.