React'te HTML Sürükle ve Bırak API'si Nasıl Kullanılır

Yayınlanan: 2022-03-10
Hızlı özet ↬ Bu eğitimde, dosya ve resim yüklemeleri için bir React sürükle ve bırak bileşeni oluşturacağız. Bu süreçte, HTML sürükle ve bırak API'sini öğreneceğiz. Ayrıca, bir React işlevsel bileşeninde durumu yönetmek için useReducer kancasının nasıl kullanılacağını öğreneceğiz.

Sürükle ve bırak API'si, HTML'nin en havalı özelliklerinden biridir. Web tarayıcılarında sürükle ve bırak özelliklerini uygulamamıza yardımcı olur.

Mevcut bağlamda, dosyaları tarayıcının dışından sürükleyeceğiz. Dosyayı/dosyaları bıraktığımızda, onları bir listeye koyarız ve isimlerini gösteririz. Dosyalar elimizdeyken, dosya(lar) üzerinde başka bir işlem gerçekleştirebiliriz, örneğin onları bir bulut sunucusuna yükleyebiliriz.

Bu eğitimde, bir React uygulamasında sürükleyip bırakma eyleminin nasıl uygulanacağına odaklanacağız. İhtiyacınız olan şey basit bir JavaScript uygulamasıysa, belki de kısa süre önce Joseph Zimmerman tarafından yazılmış mükemmel bir öğretici olan “Vanilla JavaScript ile Sürükle ve Bırak Dosya Yükleyici Nasıl Yapılır”ı okumak istersiniz.

dragenter , dragleave , dragover ve drop Olayları

Sekiz farklı sürükle ve bırak olayı vardır. Her biri, sürükle ve bırak işleminin farklı bir aşamasında tetiklenir. Bu öğreticide, bir öğe bırakma bölgesine bırakıldığında tetiklenen dördüne odaklanacağız: dragenter , dragleave , dragover ve drop .

  1. Sürüklenen bir öğe geçerli bir bırakma hedefine girdiğinde dragenter olayı tetiklenir.
  2. Sürüklenen bir öğe geçerli bir bırakma hedefi bıraktığında dragleave olayı tetiklenir.
  3. Sürüklenen bir öğe geçerli bir bırakma hedefi üzerine sürüklenirken sürüklenme olayı dragover . (Her birkaç yüz milisaniyede bir ateşlenir.)
  4. drop olayı, bir öğe geçerli bir bırakma hedefine düştüğünde, yani üzerine sürüklenip bırakıldığında tetiklenir.

ondragover ve ondrop olay işleyici niteliklerini tanımlayarak herhangi bir HTML öğesini geçerli bir bırakma hedefine dönüştürebiliriz.

Sekiz olayla ilgili her şeyi MDN web dokümanlarından öğrenebilirsiniz.

Atlamadan sonra daha fazlası! Aşağıdan okumaya devam edin ↓

Tepkideki Sürükle ve Bırak Olayları

Başlamak için eğitim deposunu bu URL'den kopyalayın:

 https://github.com/chidimo/react-dnd.git

01-start şubesine bakın. yarn de takılı olduğundan emin olun. iplikpkg.com'dan temin edebilirsiniz.

Ancak isterseniz yeni bir React projesi oluşturun ve App.js'nin içeriğini aşağıdaki kodla değiştirin:

 import React from 'react'; import './App.css'; function App() { return ( <div className="App"> <h1>React drag-and-drop component</h1> </div> ); } export default App;

Ayrıca, App.css içeriğini aşağıdaki CSS stiliyle değiştirin:

 .App { margin: 2rem; text-align: center; } h1 { color: #07F; } .drag-drop-zone { padding: 2rem; text-align: center; background: #07F; border-radius: 0.5rem; box-shadow: 5px 5px 10px #C0C0C0; } .drag-drop-zone p { color: #FFF; } .drag-drop-zone.inside-drag-area { opacity: 0.7; } .dropped-files li { color: #07F; padding: 3px; text-align: left; font-weight: bold; }

Depoyu klonladıysanız, uygulamayı başlatmak için aşağıdaki komutları (sırasıyla) verin:

 yarn # install dependencies yarn start # start the app

Bir sonraki adım, bir sürükle ve bırak bileşeni oluşturmaktır. src/ klasörü içinde bir DragAndDrop.js dosyası oluşturun. Dosyanın içine aşağıdaki işlevi girin:

 import React from 'react'; const DragAndDrop = props => { const handleDragEnter = e => { e.preventDefault(); e.stopPropagation(); }; const handleDragLeave = e => { e.preventDefault(); e.stopPropagation(); }; const handleDragOver = e => { e.preventDefault(); e.stopPropagation(); }; const handleDrop = e => { e.preventDefault(); e.stopPropagation(); }; return ( <div className={'drag-drop-zone'} onDrop={e => handleDrop(e)} onDragOver={e => handleDragOver(e)} onDragEnter={e => handleDragEnter(e)} onDragLeave={e => handleDragLeave(e)} > <p>Drag files here to upload</p> </div> ); }; export default DragAndDrop;

Return div , odak HTML olay işleyici özniteliklerimizi tanımladık. Saf HTML tek farkın deve kasası olduğunu görebilirsiniz.

onDragOver ve onDrop olay işleyici özniteliklerini tanımladığımız için div artık geçerli bir bırakma hedefidir.

Ayrıca bu olayları işlemek için işlevler tanımladık. Bu işleyici işlevlerinin her biri, olay nesnesini argümanı olarak alır.

Olay işleyicilerin her biri için, tarayıcının varsayılan davranışını yürütmesini durdurmak için preventDefault() 'u çağırırız. Varsayılan tarayıcı davranışı, bırakılan dosyayı açmaktır. Ayrıca olayın alt öğeden üst öğeye yayılmadığından emin olmak için stopPropagation() öğesini çağırırız.

DragAndDrop bileşenini App bileşenine aktarın ve başlığın altında oluşturun.

 <div className="App"> <h1>React drag-and-drop component</h1> <DragAndDrop /> </div>

Şimdi bileşeni tarayıcıda görüntüleyin ve aşağıdaki resim gibi bir şey görmelisiniz.

Boşaltma noktası
div bir bırakma bölgesine dönüştürülecek (Büyük önizleme)

Depoyu takip ediyorsanız, ilgili dal 02-start-dragndrop

useReducer Hook ile Durumu Yönetme

Bir sonraki adımımız, olay işleyicilerimizin her biri için mantığı yazmak olacaktır. Bunu yapmadan önce, bırakılan dosyaları nasıl takip etmeyi planladığımızı düşünmeliyiz. Devlet yönetimi hakkında düşünmeye başladığımız yer burasıdır.

Sürükle ve bırak işlemi sırasında aşağıdaki durumları takip edeceğiz:

  1. dropDepth
    Bu bir tamsayı olacaktır. Düşme bölgesinde kaç seviye derinlikte olduğumuzu takip etmek için kullanacağız. Daha sonra bunu bir örnekle açıklayacağım. ( Benim için bu konuya ışık tuttuğu için Egor Egorov'a teşekkür ederiz! )
  2. inDropZone
    Bu bir boole olacak. Bunu, düşme bölgesinde olup olmadığımızı takip etmek için kullanacağız.
  3. FileList
    Bu bir liste olacak. Bırakma bölgesine bırakılan dosyaları takip etmek için kullanacağız.

Durumları işlemek için React, useState ve useReducer kancalarını sağlar. Bir durumun önceki duruma bağlı olduğu durumlarla ilgileneceğimiz için useReducer kancasını tercih edeceğiz.

useReducer kancası (state, action) => newState türünde bir indirgeyici kabul eder ve bir dispatch yöntemiyle eşleştirilmiş geçerli durumu döndürür.

useReducer hakkında daha fazla bilgiyi React belgelerinde okuyabilirsiniz .

App bileşeninin içine ( return ifadesinden önce) aşağıdaki kodu ekleyin:

 ... const reducer = (state, action) => { switch (action.type) { case 'SET_DROP_DEPTH': return { ...state, dropDepth: action.dropDepth } case 'SET_IN_DROP_ZONE': return { ...state, inDropZone: action.inDropZone }; case 'ADD_FILE_TO_LIST': return { ...state, fileList: state.fileList.concat(action.files) }; default: return state; } }; const [data, dispatch] = React.useReducer( reducer, { dropDepth: 0, inDropZone: false, fileList: [] } ) ...

useReducer kancası iki bağımsız değişkeni kabul eder: bir redüktör ve bir başlangıç ​​durumu. Mevcut durumu ve durumu güncellemek için bir dispatch işlevi döndürür. Durum, bir type ve isteğe bağlı bir yük içeren bir eylem gönderilerek güncellenir. Bileşenin durumuna yapılan güncelleme, eylem türünün sonucu olarak case ifadesinden ne döndürüldüğüne bağlıdır. (Burada ilk durumumuzun bir object olduğuna dikkat edin.)

Durum değişkenlerinin her biri için, onu güncellemek üzere karşılık gelen bir vaka ifadesi tanımladık. Güncelleme, useReducer tarafından döndürülen dispatch işlevi çağrılarak gerçekleştirilir.

Şimdi data DragAndDrop dispatch props olarak gönderin :

 <DragAndDrop data={data} dispatch={dispatch} />

DragAndDrop bileşeninin en üstünde, props öğesinden her iki değere de erişebiliriz.

 const { data, dispatch } = props;

Depoyu takip ediyorsanız, karşılık gelen dal 03-define-reducers .

Olay işleyicilerimizin mantığını bitirelim. Üç noktanın iki satırı temsil ettiğine dikkat edin:

 e.preventDefault() e.stopPropagation() const handleDragEnter = e => { ... dispatch({ type: 'SET_DROP_DEPTH', dropDepth: data.dropDepth + 1 }); }; const handleDragLeave = e => { ... dispatch({ type: 'SET_DROP_DEPTH', dropDepth: data.dropDepth - 1 }); if (data.dropDepth > 0) return dispatch({ type: 'SET_IN_DROP_ZONE', inDropZone: false }) };

Aşağıdaki resimde, A ve B iç içe bırakma bölgelerine sahibiz. A bizim ilgi alanımızdır. Sürükle ve bırak olaylarını dinlemek istediğimiz yer burasıdır.

ondragenter ve ondragleave olaylarının bir gösterimi
ondragenter ve ondragleave olaylarının bir gösterimi (Büyük önizleme)

Bir bırakma bölgesine sürüklerken, bir sınıra her çarptığımızda ondragenter olayı tetiklenir. Bu, A-in ve B-in sınırlarında gerçekleşir. Bölgeye girdiğimiz için dropDepth değerini artırıyoruz.

Benzer şekilde, bir bırakma bölgesinden dışarı sürüklenirken, bir sınıra her çarptığımızda, ondragleave olayı tetiklenir. Bu, A-out ve B-out sınırlarında gerçekleşir. Bölgeden ayrıldığımız için dropDepth değerini azaltıyoruz. B-out sınırında inDropZone false olarak ayarlamadığımıza dikkat edin. Bu nedenle dropDepth'i kontrol etmek ve dropDepth işlevinden 0 büyük dönmek için bu satırı kullanıyoruz.

 if (data.dropDepth > 0) return

Bunun nedeni, ondragleave olayının tetiklenmesine rağmen hala A bölgesi içinde olmamızdır. Sadece A-out 'a bastıktan ve dropDepth şimdi 0 olduğunda inDropZone false olarak ayarladık. Bu noktada, tüm bırakma bölgelerinden ayrıldık.

 const handleDragOver = e => { ... e.dataTransfer.dropEffect = 'copy'; dispatch({ type: 'SET_IN_DROP_ZONE', inDropZone: true }); };

Bu olay her tetiklendiğinde, inDropZone true olarak ayarladık. Bu bize bırakma bölgesinin içinde olduğumuzu söylüyor. Ayrıca dataTransfer nesnesindeki dropEffect copy şekilde ayarladık. Mac'te bu, bırakma bölgesinde bir öğeyi sürüklerken yeşil bir artı işareti gösterme etkisine sahiptir.

 const handleDrop = e => { ... let files = [...e.dataTransfer.files]; if (files && files.length > 0) { const existingFiles = data.fileList.map(f => f.name) files = files.filter(f => !existingFiles.includes(f.name)) dispatch({ type: 'ADD_FILE_TO_LIST', files }); e.dataTransfer.clearData(); dispatch({ type: 'SET_DROP_DEPTH', dropDepth: 0 }); dispatch({ type: 'SET_IN_DROP_ZONE', inDropZone: false }); } };

Bırakılan dosyalara e.dataTransfer.files ile erişebiliriz. Değer, dizi benzeri bir nesnedir, bu nedenle onu bir JavaScript dizisine dönüştürmek için dizi yayılma sözdizimini kullanırız.

Şimdi, dosya dizimize eklemeye çalışmadan önce en az bir dosya olup olmadığını kontrol etmemiz gerekiyor. Ayrıca, halihazırda fileList bulunan dosyaları dahil etmemeye özen gösteriyoruz. dataTransfer nesnesi, sonraki sürükle ve bırak işlemi için hazırlanırken temizlenir. Ayrıca dropDepth ve inDropZone değerlerini de sıfırlıyoruz.

DragAndDrop bileşenindeki div className değerini güncelleyin. Bu, data.inDropZone değerine bağlı olarak div className değerini koşullu olarak değiştirir.

 <div className={data.inDropZone ? 'drag-drop-zone inside-drag-area' : 'drag-drop-zone'} ... > <p>Drag files here to upload</p> </div>

data.fileList aracılığıyla data.fileList dosyaların listesini oluşturun.

 <div className="App"> <h1>React drag-and-drop component</h1> <DragAndDrop data={data} dispatch={dispatch} /> <ol className="dropped-files"> {data.fileList.map(f => { return ( <li key={f.name}>{f.name}</li> ) })} </ol> </div>

Şimdi bırakma bölgesine bazı dosyaları sürükleyip bırakmayı deneyin. Bırakma bölgesine girdiğimizde, inside-drag-area sınıfı etkinleştirildiğinden arka planın daha az opak hale geldiğini göreceksiniz.

Bırakma bölgesi içindeki dosyaları serbest bıraktığınızda, bırakma bölgesi altında listelenen dosya adlarını göreceksiniz:

Sürükleme sırasında düşük opaklık gösteren bırakma bölgesi
Sürükleme sırasında düşük opaklık gösteren bırakma bölgesi (Büyük önizleme)
Bırakma bölgesine bırakılan dosyaların listesi
Bırakma bölgesine bırakılan dosyaların listesi (Büyük önizleme)

Bu öğreticinin tam sürümü 04-finish-handlers dalındadır.

Çözüm

HTML sürükle ve bırak API'sini kullanarak React'te dosya yüklemelerinin nasıl ele alınacağını gördük. Ayrıca useReducer kancasıyla durumu nasıl yöneteceğimizi de öğrendik. handleDrop işlevini genişletebiliriz. Örneğin, istersek dosya boyutlarını sınırlamak için başka bir kontrol ekleyebiliriz. Bu, mevcut dosyaların kontrolünden önce veya sonra gelebilir. Ayrıca, sürükle ve bırak işlevini etkilemeden bırakma bölgesini tıklanabilir hale getirebiliriz.

Kaynaklar

  • “Hooks API Reference: useReducer ”, React Docs
  • "HTML Sürükle ve Bırak API'si", MDN web belgeleri
  • "DOM Kullanarak Web ve XML Geliştirme Örnekleri", MDN web docs
  • “Vanilla JavaScript ile Sürükle ve Bırak Dosya Yükleyici Nasıl Yapılır,” Joseph Zimmerman, Smashing Magazine
  • "React'te Basit Sürükle ve Bırak Dosya Yüklemesi", Egor Egorov, Medium