Галоўная / Артыкулы

Фрагменты-рэферэнсы ў React 19.3: Паведанне DOM для груп брацоў, без кэшувальнага обертака

Дазвольце дазнацься, як рэферэнс у Fragment дае вам FragmentInstance для слухачаў, фокусу, абзэрватароў і выканання замероў між сяброўскімі элементамі, а таксама якія ёсць яго меры.

Выдавец: REACTAPP.TOP12 хв чытання2858 слоў

Крыніцы: React 19.3 Fragment Refs: Listen, Focus, Observe and Measure a Group of Elements Without a Wrapper div

Большасць кодавых базаў на React маюць элемент <div>, які існуе толькі для таго, каб ў чым-небудзь можна было размістыць ref. Можа, компонент, які вы хацелі запісаць, адрасав калькуляцыю колькісці своіх „братоў“-элементаў, альбо ён быў взяты з бібліятэкі, якая ніколі не перадавала свой ref. Такі дапаможны элемент тады нарабляе проблемы з сіткавым або гнучкым макетам, пашкоджае стайлізаванне за дапамою :nth-child або, у разе элементаў <tr>, стварае некарэктны HTML. У версіі React 19.3 Fragment Refs сталаўся стабільным: калі вы прыкрэпляеце ref да <Fragment>, вы отрымліваеце FragmentInstance, які можа выкарыстоўваць стандартныя операцыі з DOM, такія як аблекчэнне, фокусаванне, спагляданне, запіс калькуляцый і прасуванне для всіх дзецяў фрагмента адразу, не дадаючы нічога да вырасленага дрэва. У этай статыце рассказваеца пра API, практычныя падходы для кожнай з можнасцей, якія дзеці ўрабляюць кожны з методаў, а таксама пра падазры, якія трэба ведаць перш чым выклікваць код у рэальных умовах.

Паколькі гэтае функцыя ў момент напісання ўжо новая, пераканайцеся, што актуальныя даныя <Fragment> не маюць змян у назвах методаў чы робачым адносе.

API FragmentInstance

У звычайной наладзе элемент Fragment імпортуецца явна, адколькі рэферэнс існуюць толькі пасля монтавання:

import { Fragment, useRef, useEffect } from 'react';

Рэферэнс спачатку ў значэнні null, а становіцься FragmentInstance, калі фрагмент монтаваны. Наведзены выклек пазбягвае проблемам з null, дадзець слухача і адключыць яго пад час чысткі:

function Group({ children }) {
  const ref = useRef(null);            // becomes a FragmentInstance after mount
  useEffect(() => {
    const instance = ref.current;
    if (instance === null) return;
    instance.addEventListener('click', onClick);
    return () => instance.removeEventListener('click', onClick);
  }, []);
  return <Fragment ref={ref}>{children}</Fragment>;
}

Патрэбны явны элемент <Fragment>. Скрацення <>…</> не прыме яні ref, яні key. Чым забезпечваецца інстанцыя:

  • addEventListener(type, fn, opts?) і removeEventListener: працююць з дзецямі DOM першага рэвэлю, а зарэгістраваныя слухальнікі пераходзяць да дзецей, якія стваруюцца або удаляюцца пазней.
  • dispatchEvent(event): адправляе званніцу на сам фрагмент; калі задаўся параметр bubbles: true, званніца распространяецца да роднага вузла DOM.
  • focus(opts?) і focusLast(opts?): шукае ўсіх вкладзеных наследнікаў па прынцыпу глубіны, каб знайсці першы або последні элемент, які можа быць уважаны актыўным, і прыймае значэнне { preventScroll }.
  • blur(): усунея актыўны элемент, які знаходзіцца ўнутрь фрагмента, а іншыя элементы не падвергаюцца нічым.
  • observeUsing(observer) і unobserveUsing(observer): рэгіструець дзецей першага рангу DOM з IntersectionObserver або ResizeObserver; тэкстовыя вузлы не ўключаюцца.
  • getClientRects(): вяртае масэвы элемент DOMRect[] для дзецей першага рангу DOM.
  • scrollIntoView(alignToTop?): прасуе першага дзеця ў відобразэнне, калі параметр true, або последняга — калі false; прыймае толькі логічную значэнне, а параметр options выклекае памылку.
  • getRootNode() і compareDocumentPosition(node): апісваюць пазычэнне фрагмента за тымі ж правіламі, як і методы Node.
  • Адны слухач для групы дзецей

    Звычным сценарыем ёсць інструментальная палітра, якая адрасаваецца за дапамою компаненту, якім вы не кераваеце, і тады вам патрэбен аднаковы слухальнік нажатых клавіш для всіх яе кнопак, напрыклад, для аналізу дадзеных. У дэме імпортуецца:

    import { Fragment, useRef, useEffect, useState } from 'react';
    

    Toolbar — гэта компанент трэцьяго сторонньага выдавца: ён адрасаваець простыя кнопкі-браты без якога-лібо обгортка і без атрыбута ref, плюс неабяжна чатвертая кнопка. Tracked обгортае своіх дзецей у Fragment, які мае атрыбут ref, і прыўязвае обрабнавач onAny у рамках эфекту, практычна прыўязваючы яго занова, калі обрабнавач зміняецца. App фіксуе тэкст кожной нажатай кнопкі і прыладнае палочку падтверджэння, якая дазволяе дадаць ўсё новую кнопку:

    // Imagine this comes from a library: no ref, no wrapper, just siblings.
    function Toolbar({ extra }) {
      return (
        <>
          <button>Bold</button>
          <button>Italic</button>
          <button>Link</button>
          {extra && <button>Emoji</button>}
        </>
      );
    }function Tracked({ children, onAny }) {
      const ref = useRef(null);
      useEffect(() => {
        const instance = ref.current;
        if (instance === null) return;
        instance.addEventListener('click', onAny);
        return () => instance.removeEventListener('click', onAny);
      }, [onAny]);
      return <Fragment ref={ref}>{children}</Fragment>;
    }export default function App() {
      const [log, setLog] = useState([]);
      const [extra, setExtra] = useState(false);
      return (
        <>
          <div className="bar">
            <Tracked onAny={e => setLog(l => [e.target.textContent, ...l].slice(0, 6))}>
              <Toolbar extra={extra} />
            </Tracked>
          </div>
          <label><input type="checkbox" checked={extra} onChange={e => setExtra(e.target.checked)} /> add a fourth button</label>
          <p className="log">clicked: {log.join(' · ') || '—'}</p>
        </>
      );
    }
    

    Стылі выключна задаюць распалох інструментальной палітры і лініі журналу:

    .bar { display: flex; gap: 8px; margin-bottom: 10px; }
    .log { margin: 10px 0 0; font-family: ui-monospace, monospace; opacity: .8; }
    

    Увядзіце чэтвёрты кантакт і нажміце яго — ён таксама будзе зазначаны ў логу, як і іншыя. Экземпляр фрагмента сочыць за дзецячымі элементамі, калі React іх запускае і зупіняе, а таксама адкорэгуе своіх слухачоў, што ёсць самэ тыя функціі, якія інакш было бы трэба выкарыстоўваць самастаі. Зауважыце, што onAny у дэманстрацыі ўжо ёсць вбудованым функцыяйным элементам, таму эфект перэпісваецца на кожны раз, калі рэндаруецца App; у рэальным кодзе, калі такія змены маюць значэнне, стабілізавайце яго за дапамою useCallback.

    Перанесенне фокуса праз вярстакаваны контэнт

    Толькі focus() і focusLast() аналізуюць элементы за межамі першага рэвярсу. Яны праходзяць праз усіх наследнікаў у парадку глыбокага перасканавання, пакуль не знайдуць элемент, які можна надаць фокус, таму элемент уводу, які знаходзіцца ўнутрь элемента label унутрь fieldset, таксама ёсць доступным. Чыраўна «надаць фокус першаму полю ў гэтым раздэле» стае простым нават для маркапу, які не належыце вам.

    У дэме імпортуецца толькі Fragment і useRef:

    import { Fragment, useRef } from 'react';
    

    Section атрыбутуе заголовак і тры кнопкі, якія прыўязаны да функцый focus(), focusLast() і blur() у экзанплярэ фрагмента, а пасля атрыбутуе яго дзецей унутрошчы Fragment, які быў пазначаны за дапамогай useRef. App перадае два наборы поль, якія маюць введчыкі з пазначкамі:

    function Section({ title, children, controls }) {
      const ref = useRef(null);
      return (
        <>
          <div className="row">
            <strong>{title}</strong>
            <button onClick={() => ref.current.focus()}>First field</button>
            <button onClick={() => ref.current.focusLast()}>Last field</button>
            <button onClick={() => ref.current.blur()}>Blur</button>
          </div>
          <Fragment ref={ref}>{children}</Fragment>
        </>
      );
    }export default function App() {
      return (
        <Section title="Shipping">
          <fieldset>
            <legend>Address</legend>
            <label>Street <input name="street" /></label>{' '}
            <label>City <input name="city" /></label>
          </fieldset>
          <fieldset>
            <legend>Contact</legend>
            <label>Phone <input name="phone" /></label>
          </fieldset>
        </Section>
      );
    }
    

    Кольцо фокуса дапамагае побачыць рэзультат:

    .row { display: flex; gap: 8px; align-items: center; margin-bottom: 10px; }
    fieldset { border-radius: 8px; margin: 0 0 8px; }
    input:focus { outline: 3px solid light-dark(#2563eb, #60a5fa); }
    

    „Перша польна“ атрыбутуецца значэнням Street, хоць яна знаходзіцца ўнутрошчы элемента <label> у наборэ поль <fieldset>; „Пасляпэльная польна“ атрыбутуецца значэнням Phone. Глыбокая пераследаванне разлічна ад эвэнтаў і спостэрагачаў, якія зупыняюцца на першам роўні; раздзіл пра цялевыя пазначкі ніжэй пояснюе прычыны.

    Следзіць за відазнаемасцю без нарабаткі пахамоў

    observeUsing() прымае абзяральнік, які вы самі стварылі, таму вы залішаецеся пад кантролем над root, threshold і rootMargin, а экземпляр рэгіструе кожны дзецячы элемент першага рангу. У наступным прыкладзе найсвежэйшыя спісакі паведамленняў пазначаюцца як перакананыя, як толькі адна з іх стае відным у рамках прасуваннага чату. Элемент-обгортка навакола гэтых спісакоў могла бы нарабіць пахваленняя ў лейアウтэ флекс-кантэйнера, дзе кожны паведамлення вырашаецца самастойна.

    У імпортах ёсць useLayoutEffect, таму абзяральнік рэгіструецца даўна перад адрасаваннем пікселей:

    import { Fragment, useRef, useLayoutEffect, useState } from 'react';
    

    ReadReceipt стварае IntersectionObserver, які працюе з роўнем скроллу, з порогам 0.6, вызывае onRead, калі які-небудзь элементы перакрываюцца, і змаўчвае за дапамогою unobserveUsing. App адрасавае чатырнацаць паведамленняў, а последнія тры знаходзяцца ў ReadReceipt:

    function ReadReceipt({ root, onRead, children }) {
      const ref = useRef(null);
      useLayoutEffect(() => {
        const instance = ref.current;
        const io = new IntersectionObserver(
          entries => { if (entries.some(e => e.isIntersecting)) onRead(); },
          { root: root.current, threshold: 0.6 }
        );
        instance.observeUsing(io);
        return () => instance.unobserveUsing(io);
      }, [root, onRead]);
      return <Fragment ref={ref}>{children}</Fragment>;
    }const MESSAGES = Array.from({ length: 14 }, (_, i) => `Message ${i + 1}`);export default function App() {
      const pane = useRef(null);
      const [read, setRead] = useState(false);
      return (
        <>
          <p className="status">{read ? '✅ Priya has read your last messages' : 'scroll the pane to the bottom…'}</p>
          <div className="pane" ref={pane}>
            {MESSAGES.slice(0, 11).map(m => <div key={m} className="bubble">{m}</div>)}
            <ReadReceipt root={pane} onRead={() => setRead(true)}>
              {MESSAGES.slice(11).map(m => <div key={m} className="bubble mine">{m}</div>)}
            </ReadReceipt>
          </div>
        </>
      );
    }
    

    CSS ператварае роўень у скроллаваны стовпчак тыпу flex і выравнюе власныя паведамлення корыстувальца праваю сторонай:

    .status { margin: 0 0 8px; font-weight: 600; }
    .pane { height: 190px; overflow: auto; display: flex; flex-direction: column; gap: 6px; padding: 8px; border-radius: 10px; background: light-dark(#f1f5f9, #262a33); }
    .bubble { align-self: flex-start; padding: 6px 10px; border-radius: 12px; background: light-dark(#fff, #363b47); }
    .mine { align-self: flex-end; background: light-dark(#dbeafe, #1e3a5f); }
    

    ResizeObserver працуе аднойчы. Калі вы керуеце большам чысла груп, якія выкарыстоўваюць аднаковыя настройкі назірання, вам не патрэбны спостэрэльнікі для кожной групы: кожны первасортны дзеціні элемент несе атрыбут reactFragments, які мае Set з екземплярамі фрагментаў, да якіх ён належыць, што дазволяе аднаму спостэрэльніку знаходзіць відпаведную групу для кожнага элемента і вызываць правы працоўнік.

    Зьвяржоўка групы брацоў і сестэр

    getClientRects() вяртае адны прарактанг у кожнам дзецінскім элеменце першага рангу. Іх сумаванне дае рамку, якая абграўляе всю групу, і яю можна выкарыстаць для падсвечвання выбранага элемента або стварэння рамкі навакол калькulaцыйных поль, не паўтараючы структуру лейауту, у якім знаходзяцца эты элементы.

    У дэманстрацыі імпортуецца:

    import { Fragment, useRef, useState, useLayoutEffect } from 'react';
    

    Outline чытае прарактангі ў эфекце лейауту, калі гэты эфект становіцца актыўным, вычысляе мінімальныя значэння для верхней і левай граней, а таксама максімальныя для ніжней і правай граней, дадае зсувы прасування і невялікі запас, а потым зберагае рэзультат. Пасля чого ён адрасавае абсалютна распакованую рамку пры самай фрагментацыі. App размешчае две групы по трох элементаў у аднай сетцы і дазволяе выбраць, калкulaцыйныя поля трэба абграўляць:

    function Outline({ active, children }) {
      const ref = useRef(null);
      const [box, setBox] = useState(null);
      useLayoutEffect(() => {
        if (!active) return setBox(null);
        const rects = ref.current.getClientRects();
        const top = Math.min(...rects.map(r => r.top)), left = Math.min(...rects.map(r => r.left));
        const bottom = Math.max(...rects.map(r => r.bottom)), right = Math.max(...rects.map(r => r.right));
        setBox({ top: top + scrollY - 6, left: left + scrollX - 6, width: right - left + 12, height: bottom - top + 12 });
      }, [active]);
      return (
        <>
          <Fragment ref={ref}>{children}</Fragment>
          {box && <div className="outline" style={box} />}
        </>
      );
    }export default function App() {
      const [which, setWhich] = useState('none');
      return (
        <>
          <div className="row">
            {['none', 'address', 'card'].map(w => (
              <label key={w}><input type="radio" checked={which === w} onChange={() => setWhich(w)} /> {w}</label>
            ))}
          </div>
          <div className="grid">
            <Outline active={which === 'address'}>
              <input placeholder="Street" /><input placeholder="City" /><input placeholder="PIN" />
            </Outline>
            <Outline active={which === 'card'}>
              <input placeholder="Card number" /><input placeholder="MM/YY" /><input placeholder="CVV" />
            </Outline>
          </div>
        </>
      );
    }
    

    Сетка складаецца з трох столбцоў, а контур размешчаны абсалютна з параметрам pointer-events: none, таму ён ніколі не перэхопляе клікі:

    .row { display: flex; gap: 14px; margin-bottom: 10px; }
    .grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
    .grid input { min-width: 0; }
    .outline { position: absolute; pointer-events: none; border: 2px dashed light-dark(#dc2626, #f87171); border-radius: 8px; }
    

    Кожны элемент уведзення ў даным разе яўляецца безпосерэднім дзецячым элементам той самай CSS-сеткі. Якбы кожную групу пакаваць у <div>, тады ўсе трое елементаў уведзення былі б запакаваныя ў адну клетку; за дапамогою фрагмента сетка застаецца незменнай, і кожную групу все ўсё можна ўзяць пад расчыт. Аднай з абмежэнняў дамаўкі ёсць тое, што розмеры кантэйнера вычысляюцца толькі колі змяніўся статус active, таму падзеяўкі вікна або рух кантэйнера з прасуванням заставяюць розмеры старымі. Яго можна выправіць, супаравняўшы з ResizeObserver за дапамогою методу observeUsing.

    Калькі дзецячыя элементы прымае кожны метод

    Большасць методаў працуюць з тым, што React называе дзецьмі хоста першага рангу, тыято з элементамі DOM, да якіх можна дасягнуць, спускаючыся праз компоненты React пакуль не будзе знайдзены рэальны элемент. Элементы, якія знаходзяцца ўнутрь іх, не являюцца прымарнымі цілямі.

    <Fragment ref={ref}>
      <div id="A" />
      <Wrapper>              {/* a component, not a DOM node: looked through */}
        <div id="B">
          <div id="C" />     {/* inside a DOM node: NOT targeted */}
        </div>
      </Wrapper>
      <div id="D" />
    </Fragment>
    // addEventListener / observeUsing / getClientRects → A, B, D
    // focus / focusLast → search A, B, C, D depth-first
    

    У гэтым дрэве Wrapper ёсць компонент, таму React аналізуе яго, і B лячыцца элементам першага рангу. C знаходзіцца ўнутрь элемента DOM B, таму яны не ўважаюцца прымарнымі цілямі. Таму слухачы, абзэры і праекты прыкладаны да A, B і D, тады калі focus і focusLast шукаюць у A, B, C і D у парадку глыбокага спуску.

    Разлік ўмышлены. Адтакуль, калі эвэнты распространяюцца па прынцыпу „баблінг“, клікі ўнутры C ужо доходзяць да аберанта ў B, а касета і спостэрэння B ужо абягаюць C. У фокусе нэт такога аналагу, і элемент, які можа прымець фокус, можа знаходзіцца на будзь-яй глыбіні, таму гэтыя два методы вынужданы шукаць.

    Альтэрнатывныя способы

    До появы Fragment Refs існавалі тры распашчытныя падходы, кожны з якіх меў сваю цэну:

    • Элемент-обгортка, <div ref={ref}><Thing /></div>: ён дадае новы элемент flex або grid там, дзе раней быў рад братоўскіх элементаў, нарушае селектары :first-child і :nth-child, дадае касету для макетавання, і ёсць абсалютна недзейны між радкамі таблыцы або элементамі спісу.
  • Змена компаненту так, каб ён перадаваў свой ref або прымеў атрыбут innerRef: гэта працюе для вашага сабскоду, але немагчыма для пакета, і ўсё рав дае толькі адзін вузол.
  • Запытка DOM з ref-а абоцевіка, напрыклад parent.querySelectorAll('button') унутры эфекту: гэта не працюе, калі дзецявы элементы зміняюцца пасля запуску эфекту, і застаецца стары набор слухачаў.
  • Чаму гэта корыстна

    За дапамою Fragment Refs можна дадзіць додатковыя функцыі к маркапу трэціх сторон, заставаючы гэты маркап абсалютна такім, які ён. Гэта спрыяе ствароўцы семіі складовых, якія маюць толькі функцыі: <Tracked>, <InView>, <FocusScope>, <Outline>. Кожная з іх — гэта фрагмент плюс эфект, які працюе з будзь-якімі дзецямі элементаў і нічога не дадае да DOM. Найбольшыя выгоды отрымаюць стваральнікі сістэм дызайну; складовая Menu можа кераваць фокусам між элементамі, якія відрасцелі ў корыстувача, не нав’язваючы ўпорадкування гэтым элементам. У хроніцы змян React гэта опісвае як композабельная платформеная функцыя, што ёсць хорашым ментальным мадэляваннем: фрагмент — гэта месца, дзе знаходзіцца функцыя, а дзеці можу быць чым завгодна.

    Проблемы, якія трэба пераканацца перад выкарыстоўванням

    • Для ref неабходна довгая форма; <> яе не прыйме.
  • Даўжыню часу, які застоіцца рэферэнс пры ўстановцы, можна з’ясавіць толькі пасля ёй, таму кожны эфект павінен спачатку пераканацца ў ее значэнні null.
  • Методы-слухачы, спостэрагувальнікі і методы вімеры аналізуют толькі одны рэвень DOM, тады калі два методы фокусу праходзяць праз усю паддрэво.
  • Метод scrollIntoView прыймае толькі логічную вялічыну. Перадача { behavior: 'smooth' } вызывае адхэнне. Чырагайце scrollIntoView(), каб першы элемент быў выравняны з верхам, або scrollIntoView(false), каб последні элемент быў выравняны з ніжней часткай.
  • Фрагменты, якія маюць толькі тэкст, не можна спостэрагаць, адтуды ўжо таму, што метод observeUsing прызначаны для элементаў; React павярамляе пра гэта пад час розработы.
  • Унутры схованай дрэва <Activity> слухачы, даданыя пад час сховання, прыўязуюцца толькі тады, калі паддрэво стане візуабельным.
  • Версія 19.3 выправіла проблему вітэчкі аслухальніка (#36047): параметры захоплення не былі нормалізаваны так, як тагучаеся DOM, і гэта значыла, што рэўістрацыя з { capture: true } і анрэўістрацыя з простага true заставлялі аслухальнік застацца прыўязаным. Бяжучы на стабільную версію, пераканайцеся, што вы корыстаецеся аслухальнікамі фазы захоплення.
  • focus() залежыць ад таго, каб вікно мела фокус у операцыйной сістэме. React падтверджае, што элемент прыме фокус, чакаючы на свой адбудовы focus, тады як Chrome прахоўвае гэты адбудовы, калі вікно браузера не ў стане актыўнасці. У тэстах без вікна або на фоне было зафіксавана, што focusLast() пераходзіць да элемента Phone і заставляе фокус на Street, таму пераканайцеся, што тэставая стороніца дзейсна мае фокус, перш чым пераканацца, дзе ён знаходзіцца.
  • FragmentInstance не ўтварае элемента, таму такі атрыбуты як classList, style і innerHTML на ям не існуе; для всьго, што ўпэўненася ў іх наявнасці, паказваецца неабходнасць вікорыстоўваць справжній DOM-вузел.
  • Альтэрнатыва для React 19.2 і ранэйшых версіяў

    У разе вікорыстоўвання слухача, найболей разумным заменнікам ёсць дэлегаванне запуску адбування падзеяў з боку роднічага элемента. Паколькі функцыя апрацоўкі падзеяў знаходзіцца на роднічым элеменце і пераказвае e.target.closest('button'), дзеціны элементы можу з’являцца і знікаць без неабходнасці паўтарнага прыўязвання.

    function Tracked({ children, onAny }) {
      const parent = useRef(null);
      useEffect(() => {
        const el = parent.current;
        const handler = (e) => { if (e.target.closest('button')) onAny(e); };
        el.addEventListener('click', handler);
        return () => el.removeEventListener('click', handler);
      }, [onAny]);
      return <div ref={parent} style={{ display: 'contents' }}>{children}</div>;
    }
    

    Стаянне display: contents усунеяе сабе ўласны контэйнер, таму элементы, якія знаходзяцца ўнутры, адносуюцца да бацькіх элементаў тыпу flex і grid як прымусовыя елементы. Хоць гэты элемент застаецца самастоятным, яго нельга размешчаць унутры <table>; прылады для чытання экрана і падобныя інструменты іноды спрацоўваюць з яму некорэктна, а для вімеры чы ўважлівага адстэйкання да іншых элементаў все раве трэба вікорыстоўваць querySelectorAll. Гэта падходзіць для прыемнікаў сігналаў і керавання фокусам, але у віпадках спостэрэння і вімеры дасканальна патрэбны версія 19.3.

    Ключовыя выводы

    • Вікорыстоўванне ref для явнага <Fragment> дае FragmentInstance, які аб’еднвае прыемнікі сігналаў, керавання фокусам, спостэрэнне, вімеру і прасуванне між сябрамі элементаў без дадатковых вузлаў DOM.
    • Прыемнікі сігналаў і прыстроі спостэрэння застаюцца сінхроннымі, калі элементы дадаюцца чы адключаюцца, таму не трэба ручнага ведання стану.
  • Большасць методаў нацэленыя на дзецей хоста першага рангу; толькі focus і focusLast шукаюць у всім паддрэве, таму ўжо focus не адбываецца па прынцыпу „баблінгу“.
  • Зверніце увагу на важлівыя аспекты: scrollIntoView, які працуе толькі з булевымі значэннямі, адсутнае назіранне толькі за тэкстам, фокус вакна пад час тэстаў і практыка выкарыстання capture-listener у версіі 19.3.
  • Кампоненты, якія займаюцься толькі біяверамі, такія як трэйкінг, візыбільнасць і фокус, стаюць простымі, можна перадаць у вжытак компонентамі.
  • Пэўны спіс усіх методаў і асаблівасцяў можна пазнакаміць у афіцыйной даследчай документацыі Fragment; супаўзяныя прыгласы да змены знаходзяцца ў хроніцы змян праекта.