<Fragment> (<>...</>)
<Fragment>, genellikle <>...</> syntax’ı ile kullanılır ve element’leri bir wrapper node olmadan gruplamanızı sağlar.
<>
<AltEleman />
<BaskaAltEleman />
</>- Referans
- Kullanım
- Birden Fazla Eleman Döndürme
- Bir değişkene birden fazla eleman atama
- Metinle elemanları gruplama
- Fragment’lar listesini oluşturma:
- Canary only Wrapper element olmadan event listener ekleme
- Canary only Bir grup element üzerinde focus yönetme
- Canary only Bir grup elementi görünüme kaydırma
- Canary only Wrapper element olmadan visibility observe etme
- Canary only Global IntersectionObserver cache’leme
Referans
<Fragment>
Tek bir elemana ihtiyaç duyduğunuz durumlarda, elemanları <Fragment> içine alarak onları bir araya getirebilirsiniz. Fragment içinde elemanları gruplamak, sonuç DOM üzerinde herhangi bir etkiye sahip değildir; sanki elemanlar gruplanmamış gibi aynı kalır. Boş JSX etiketi <></> çoğu durumda <Fragment></Fragment> için kısaltmadır.
Prop’lar
- optional
key: Açık<Fragment>syntax’iyle tanımlanan Fragment’lar key’lere sahip olabilir. - Canary only optional
ref: Bir ref object’i (örn.useRef’ten gelen) veya callback function. React, ref value olarak Fragment tarafından sarılan DOM node’larıyla etkileşim kurmak için method’lar implemente eden birFragmentInstancesağlar.
Uyarılar
-
Bir Fragment’a
keygeçirmek istiyorsanız,<>...</>syntax’ini kullanamazsınız.'react'içindenFragment’ı açıkça import etmeniz ve<Fragment key={yourKey}>...</Fragment>şeklinde render etmeniz gerekir. -
React,
<><Child /></>render etmekten[<Child />]render etmeye geçtiğinizde veya geri döndüğünüzde ya da<><Child /></>render etmekten<Child />render etmeye geçtiğinizde ve geri döndüğünüzde state’i resetlemez. Bu yalnızca tek bir seviye derinlikte çalışır: örneğin,<><><Child /></></>yapısından<Child />yapısına geçmek state’i resetler. Kesin semantiklere buradan bakabilirsiniz. -
Canary only Bir Fragment’a
refgeçirmek istiyorsanız,<>...</>syntax’ini kullanamazsınız.'react'içindenFragment’ı açıkça import etmeniz ve<Fragment ref={yourRef}>...</Fragment>şeklinde render etmeniz gerekir.
Canary only FragmentInstance
Bir Fragment’a ref geçirdiğinizde, React bir FragmentInstance object’i sağlar. Bu object, Fragment tarafından sarılan birinci seviye DOM child’larıyla etkileşim kurmak için method’lar implemente eder.
addEventListenerveremoveEventListener, tüm birinci seviye DOM child’ları üzerinde event listener’ları yönetir.dispatchEvent, Fragment üzerinde bir event dispatch eder; bu event DOM parent’a bubble olabilir.focus,focusLastveblur, tüm nested child’lar üzerinde depth-first şekilde focus’u yönetir.observeUsingveunobserveUsing,IntersectionObserverveyaResizeObserverinstance’larını attach ve detach eder.getClientRects, tüm birinci seviye DOM child’larının bounding rectangle’larını döndürür.getRootNode, Fragment’ın parent’ının root node’unu döndürür.compareDocumentPosition, Fragment’ın konumunu başka bir node ile karşılaştırır.scrollIntoView, Fragment’ın child’larını görünüme kaydırır.
addEventListener(type, listener, options?)
Fragment’ın tüm birinci seviye DOM child’larına bir event listener ekler.
fragmentRef.current.addEventListener('click', handleClick);Parametreler
type: Dinlenecek event type’ını temsil eden bir string (örn.'click','focus').listener: Event handler function.- optional
options: DOMaddEventListenerAPI’siyle eşleşen, capture için kullanılan bir options object’i veya boolean.
Returns
addEventListener herhangi bir şey döndürmez (undefined).
removeEventListener(type, listener, options?)
Fragment’ın tüm birinci seviye DOM child’larından bir event listener’ı kaldırır.
fragmentRef.current.removeEventListener('click', handleClick);Parametreler
type: Event type string’i.listener: Kaldırılacak event handler function.- optional
options: DOMremoveEventListenerAPI’siyle eşleşen bir options object’i veya boolean.
Returns
removeEventListener herhangi bir şey döndürmez (undefined).
dispatchEvent(event)
Fragment üzerinde bir event dispatch eder. Eklenen event listener’lar çağrılır ve event Fragment’ın DOM parent’ına bubble olabilir.
fragmentRef.current.dispatchEvent(new Event('custom', { bubbles: true }));Parametreler
event: Dispatch edilecek birEventobject’i. Eğerbubblestrueise, event Fragment’ın parent DOM node’una bubble olur.
Returns
Event cancel edilmediyse true, preventDefault() çağrıldıysa false.
focus(options?)
Fragment içindeki ilk focusable DOM node’una focus eder. Bir DOM element üzerinde element.focus() çağırmaktan farklı olarak, bu method yalnızca elementin kendisini veya direct child’larını değil, focusable bir element bulana kadar tüm nested child’ları depth-first şekilde arar.
fragmentRef.current.focus();Parametreler
- optional
options: BirFocusOptionsobject’i (örn.{ preventScroll: true }).
Returns
focus herhangi bir şey döndürmez (undefined).
focusLast(options?)
Fragment içindeki son focusable DOM node’una focus eder. Nested child’ları depth-first şekilde arar, ardından ters sırada iterate eder.
fragmentRef.current.focusLast();Parametreler
- optional
options: BirFocusOptionsobject’i.
Returns
focusLast herhangi bir şey döndürmez (undefined).
blur()
Active element Fragment içindeyse focus’u kaldırır. Eğer document.activeElement Fragment içinde değilse, blur hiçbir şey yapmaz.
fragmentRef.current.blur();Returns
blur herhangi bir şey döndürmez (undefined).
observeUsing(observer)
Sağlanan observer ile Fragment’ın tüm birinci seviye DOM child’larını observe etmeye başlar.
const observer = new IntersectionObserver(callback, options);
fragmentRef.current.observeUsing(observer);Parametreler
observer: BirIntersectionObserverveyaResizeObserverinstance’ı.
Returns
observeUsing herhangi bir şey döndürmez (undefined).
unobserveUsing(observer)
Belirtilen observer ile Fragment’ın DOM child’larını observe etmeyi durdurur.
fragmentRef.current.unobserveUsing(observer);Parametreler
observer: Daha önceobserveUsing’e geçirilen aynıIntersectionObserverveyaResizeObserverinstance’ı.
Returns
unobserveUsing herhangi bir şey döndürmez (undefined).
getClientRects()
Tüm birinci seviye DOM child’larının bounding rectangle’larını temsil eden DOMRect object’lerinden oluşan flat bir array döndürür.
const rects = fragmentRef.current.getClientRects();Returns
Tüm child’ların bounding rectangle’larını içeren bir Array<DOMRect>.
getRootNode(options?)
Node.getRootNode() davranışıyla eşleşecek şekilde, Fragment’ın parent DOM node’unu içeren root node’u döndürür.
const root = fragmentRef.current.getRootNode();Parametreler
- optional
options: DOMgetRootNodeAPI’siyle eşleşen,composedboolean property’sine sahip bir object.
Returns
Bir Document, ShadowRoot veya parent DOM node yoksa FragmentInstance’ın kendisi.
compareDocumentPosition(otherNode)
Compares the document position of the Fragment with another node, returning a bitmask matching the behavior of Node.compareDocumentPosition().
const position = fragmentRef.current.compareDocumentPosition(otherElement);Parameters
otherNode: The DOM node to compare against.
Returns
A bitmask of position flags. Empty Fragments and Fragments with children rendered through a portal include Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC in the result.
scrollIntoView(alignToTop?)
Fragment’ın child’larını görünüme kaydırır. alignToTop true olduğunda veya atlandığında, ilk child’ı scrollable ancestor’ın üst kısmıyla hizalayacak şekilde kaydırır. alignToTop false olduğunda, son child’ı alt kısımla hizalayacak şekilde kaydırır.
fragmentRef.current.scrollIntoView();Parametreler
- optional
alignToTop: Bir boolean.trueise (default), ilk child’ı scrollable area’nın üst kısmına kaydırır.falseise, son child’ı alt kısma kaydırır.Element.scrollIntoView()’dan farklı olarak, bu method birScrollIntoViewOptionsobject’i kabul etmez.
Döndürür
scrollIntoView herhangi bir şey döndürmez (undefined).
Uyarılar
scrollIntoViewbir options object’i kabul etmez. Bir object geçirmek hata fırlatır. Bunun yerinealignToTopboolean’ını kullanın.- Fragment’ın child’ı yoksa,
scrollIntoViewfallback olarak en yakın sibling’i veya parent’ı görünüme kaydırır.
FragmentInstance Uyarıları
- Child’ları hedefleyen method’lar (
addEventListener,observeUsingvegetClientRectsgibi), Fragment’ın birinci seviye host (DOM) child’ları üzerinde çalışır. Başka bir DOM element içinde nested olan child’ları doğrudan hedeflemezler. focusvefocusLast, focusable element’leri bulmak için nested child’ları depth-first şekilde arar; event ve observer method’ları ise yalnızca birinci seviye host child’ları hedefler.observeUsingtext node’lar üzerinde çalışmaz. Fragment yalnızca text child’ları içeriyorsa React development ortamında bir warning loglar.- React,
addEventListenerile eklenen event listener’ları gizli<Activity>tree’lerine uygulamaz. BirActivityboundary hidden’dan visible’a geçtiğinde, listener’lar otomatik olarak uygulanır. ref’e sahip bir Fragment’ın her birinci seviye DOM child’ı birreactFragmentsproperty’si alır: element’i sahiplenen tüm Fragment instance’larını içeren birSet<FragmentInstance>. Bu, birden fazla Fragment arasında shared observer cache’lemeyi mümkün kılar.
Kullanım
Birden Fazla Eleman Döndürme
Fragment veya, <>...</> sözdizimini kullanmak birden fazla elemanı bir araya getirir. Tek bir elemanın gidebileceği herhangi bir yere birden fazla eleman koymak için kullanabilirsiniz. Örneğin, bir bileşen sadece bir eleman döndürebilir, ancak Fragment kullanarak birden fazla elemanı bir araya getirebilir ve onları bir grup olarak döndürebilirsiniz:
function Post() {
return (
<>
<PostTitle />
<PostBody />
</>
);
}Fragmanlar kullanışlıdır çünkü bir Fragment ile elemanları gruplamak, elemanları bir DOM elemanı gibi başka bir konteynerde sarmak gibi düzeni veya stilleri etkilemez. Tarayıcı araçlarıyla bu örneği incelediğinizde, tüm <h1> ve <p> DOM düğümlerinin etrafında sarmalayıcı olmadan kardeşler olarak görünecektir.
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> ); }
Derinlemesine İnceleme
Yukarıdaki örnek, React’ten Fragment içe aktarmaya eşdeğerdir:
import { Fragment } from 'react';
function Post() {
return (
<Fragment>
<PostTitle />
<PostBody />
</Fragment>
);
}Genellikle bunun gibi bir şeye ihtiyaç duymazsınız, ancak [Fragment’a key eklemek] istediğinizde kullanabilirsiniz.(#rendering-a-list-of-fragments)
Bir değişkene birden fazla eleman atama
Diğer tüm elemanlar gibi, Fragment elemanlarını değişkenlere atayabilir, bunları props olarak iletebilir ve benzeri işlemler yapabilirsiniz:
function CloseDialog() {
const buttons = (
<>
<OKButton />
<CancelButton />
</>
);
return (
<AlertDialog buttons={buttons}>
Are you sure you want to leave this page?
</AlertDialog>
);
}Metinle elemanları gruplama
Fragment ile, metni bileşenlerle bir araya getirmek için kullanabilirsiniz:
function DateRangePicker({ start, end }) {
return (
<>
From
<DatePicker date={start} />
to
<DatePicker date={end} />
</>
);
}Fragment’lar listesini oluşturma:
İşte <></> sözdizimini yerine Fragment yazmanız gereken bir durum. Bir döngüde birden fazla elemanı oluşturduğunuzda, her elemana bir key atamanız gerekmektedir. Eğer döngü içindeki elemanlar Fragment ise, key özelliğini sağlamak için normal JSX eleman sözdizimini kullanmanız gerekir:
function Blog() {
return posts.map(post =>
<Fragment key={post.id}>
<PostTitle title={post.title} />
<PostBody body={post.body} />
</Fragment>
);
}DOM’u, Fragment alt elemanlarının etrafında sarmalayıcı öğe olmadığını doğrulamak için inceleyebilirsiniz:
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 Wrapper element olmadan event listener ekleme
Fragment refleri, wrapper DOM node’u eklemeden bir grup elemente event listener eklemenizi sağlar. Listener’ları attach etmek ve cleanup yapmak için bir ref callback kullanın:
import { Fragment, useState, useRef, useEffect } from 'react'; function ClickableFragment({ children, onClick }) { const fragmentRef = useRef(null); useEffect(() => { const fragmentInstance = fragmentRef.current; if (fragmentInstance === null) { return; } fragmentInstance.addEventListener('click', onClick); return () => { fragmentInstance.removeEventListener( 'click', onClick ); }; }, [onClick]) return ( <Fragment ref={fragmentRef}> {children} </Fragment> ); } export default function App() { const [clicks, setClicks] = useState(0); return ( <> <p>Total clicks: {clicks}</p> <ClickableFragment onClick={() => { setClicks(c => c + 1); }}> <button>Button A</button> <button>Button B</button> <button>Button C</button> </ClickableFragment> </> ); }
addEventListener çağrısı, listener’ı Fragment’ın her birinci seviye DOM child’ına uygular. Child’lar dinamik olarak eklendiğinde veya kaldırıldığında, FragmentInstance listener’ı otomatik olarak ekler veya kaldırır.
Derinlemesine İnceleme
Bir FragmentInstance, Fragment’ın birinci seviye host (DOM) child’larını hedefler. Şu tree’yi düşünün:
<Fragment ref={ref}>
<div id="A" />
<Wrapper>
<div id="B">
<div id="C" />
</div>
</Wrapper>
<div id="D" />
</Fragment>Wrapper bir React component’i olduğu için, FragmentInstance DOM node’larını bulmak üzere onun içinden geçerek bakar. Hedeflenen child’lar A, B ve D’dir. C hedeflenmez çünkü DOM elementi B içinde nested durumdadır.
addEventListener, observeUsing ve getClientRects gibi method’lar bu birinci seviye DOM child’ları üzerinde çalışır. focus ve focusLast farklıdır; focusable element’leri bulmak için tüm nested child’ları depth-first şekilde ararlar.
Canary only Bir grup element üzerinde focus yönetme
Fragment refleri, Fragment içindeki tüm DOM node’ları üzerinde çalışan focus, focusLast ve blur method’larını sağlar:
import { Fragment, useRef } from 'react'; function FormFields({ children }) { const fragmentRef = useRef(null); return ( <> <div className="buttons"> <button onClick={() => { fragmentRef.current.focus(); }}> Focus first </button> <button onClick={() => { fragmentRef.current.focusLast(); }}> Focus last </button> <button onClick={() => { fragmentRef.current.blur(); }}> Blur </button> </div> <Fragment ref={fragmentRef}> {children} </Fragment> </> ); } // Even though the inputs are deeply nested, // focus() searches depth-first to find them. export default function App() { return ( <FormFields> <fieldset> <legend>Shipping</legend> <label> Street: <input name="street" /> </label> <label> City: <input name="city" /> </label> </fieldset> </FormFields> ); }
focus() çağırmak street input’una focus eder; bu input bir <fieldset> ve <label> içinde nested olsa bile. focus(), yalnızca Fragment’ın direct child’larını değil, tüm nested child’ları depth-first şekilde arar. focusLast() aynı işlemi ters yönde yapar ve blur(), currently focused element Fragment içindeyse focus’u kaldırır.
Canary only Bir grup elementi görünüme kaydırma
Wrapper element olmadan bir Fragment’ın child’larını görünüme kaydırmak için scrollIntoView kullanın. İlk child’ı en üste kaydırmak için true geçirin (veya argümanı atlayın). Son child’ı en alta kaydırmak için false geçirin:
import { Fragment, useRef } from 'react'; function ScrollableSection({ children }) { const fragmentRef = useRef(null); return ( <> <div className="buttons"> <button onClick={() => { fragmentRef.current.scrollIntoView(); }}> Scroll to top </button> <button onClick={() => { fragmentRef.current.scrollIntoView(false); }}> Scroll to bottom </button> </div> <div className="container"> <Fragment ref={fragmentRef}> {children} </Fragment> </div> </> ); } const items = []; for (let i = 1; i <= 25; i++) { items.push('Item ' + i); } export default function App() { return ( <ScrollableSection> <h3>Section Start</h3> {items.map((item) => ( <p key={item}>{item}</p> ))} <h3>Section End</h3> </ScrollableSection> ); }
Canary only Wrapper element olmadan visibility observe etme
Bir Fragment’ın tüm birinci seviye DOM child’larına IntersectionObserver attach etmek için observeUsing kullanın. Bu, child component’lerin ref expose etmesini veya wrapper element eklemeyi gerektirmeden visibility’yi track etmenizi sağlar:
import { Fragment, useRef, useLayoutEffect, useState, } from 'react'; import Card from './Card'; function VisibleGroup({ onVisibilityChange, children }) { const fragmentRef = useRef(null); useLayoutEffect(() => { const visibleElements = new Set(); const observer = new IntersectionObserver( (entries) => { entries.forEach(e => { if (e.isIntersecting) { visibleElements.add(e.target); } else { visibleElements.delete(e.target); } }); onVisibilityChange(visibleElements.size > 0); } ); const fragmentInstance = fragmentRef.current; fragmentInstance.observeUsing(observer); return () => { fragmentInstance.unobserveUsing(observer); }; }, [onVisibilityChange]); return ( <Fragment ref={fragmentRef}> {children} </Fragment> ); } export default function App() { const [isVisible, setIsVisible] = useState(true); return ( <div className={isVisible ? 'page visible' : 'page'}> <div className="filler">Scroll down</div> <VisibleGroup onVisibilityChange={setIsVisible}> <Card title="First section" /> <Card title="Second section" /> </VisibleGroup> <div className="filler">Scroll up</div> </div> ); }
Canary only Global IntersectionObserver cache’leme
Çok sayıda observer’a sahip siteler için yaygın bir performance optimization, config başına tek bir IntersectionObserver paylaşmak ve entry’lerini hangi element’in intersect ettiğine göre doğru callback’lere yönlendirmektir. Fragment refleri, reactFragments property’si üzerinden aynı pattern’i destekler.
ref’e sahip bir Fragment’ın her birinci seviye DOM child’ında bir reactFragments property’si bulunur: bu element’i içeren FragmentInstance object’lerinden oluşan bir Set. Shared observer tetiklendiğinde, intersect eden element’in hangi FragmentInstance’a ait olduğunu bulmak ve doğru callback’leri çalıştırmak için bu property’yi kullanabilirsiniz.
import { useState, useCallback } from 'react'; import ObservedGroup from './ObservedGroup'; import Card from './Card'; export default function App() { const [bgColor, setBgColor] = useState(null); const onGreen = useCallback((entry) => { if (entry.isIntersecting) { setBgColor('#d4edda'); } }, []); const onBlue = useCallback((entry) => { if (entry.isIntersecting) { setBgColor('#cce5ff'); } }, []); return ( <div className="page" style={{ background: bgColor || 'white', }}> <div className="filler">Scroll down</div> <ObservedGroup onIntersection={onGreen}> <Card title="Green section" className="green" /> </ObservedGroup> <div className="filler" /> <ObservedGroup onIntersection={onBlue}> <Card title="Blue section" className="blue" /> </ObservedGroup> <div className="filler">Scroll up</div> </div> ); }
Aynı options’a sahip birden fazla ObservedGroup component’i tek bir IntersectionObserver’ı yeniden kullanır. Herhangi bir section görünüme kaydırıldığında, shared observer tetiklenir ve entry’yi doğru callback’e yönlendirmek için reactFragments’ı kullanır.