เอาล่ะ ต่อกันมาจากบทความก่อนหน้าที่เราได้พูดถึง Cloudinary กันไปแล้ว ได้มีการพูดเกริ่น ๆ ถึงเจ้า Dropzone กันไปแล้ว ในบทความนี้เราก็จะมาแนะนำเจ้า library ตัวนี้ที่จะทำให้ระบบอัปโหลดภาพของเรานั้นสุดเจ๋งกันขึ้นไปอีกขั้นด้วยการลากวางไฟล์เพื่ออัปโหลด ไม่ต้องพูดพร่ำทำเพลง เรามาเริ่มกันเลยดีกว่า
เขียนโดย
Thanawat Udchachon
Internship @ borntoDev
เริ่มต้นการใช้งาน
เจ้าตัว react-dropzone เนี่ย มันก็เป็น React hook ง่าย ๆ ตัวหนึ่งที่ใช้สำหรับการทำส่วนของการลากวางไฟล์ และเช่นเคยสำหรับการจะใช้ library อะไร เราก็ต้องทำการติดตั้งกันก่อน ซึ่งก็สามารถทำได้ด้วยคำสั่ง npm install react-dropzone
ส่วนตัวโค้ด เพื่อเป็นการไม่เสียเวลา เราก็จะเริ่มจากโค้ดที่เราได้ทำไปกันตั้งแต่บทความก่อนหน้านะครับ
import React, { useState } from 'react'; import Axios from 'axios'; export default function Upload() { Axios.defaults.withCredentials = true; const [imageFile, setImageFile] = useState(''); const handleFileInputChange = (e) => { const file = e.target.files[0]; const reader = new FileReader(); reader.readAsDataURL(file); reader.onloadend = () => { setImageFile(reader.result); } } const handleSubmitFile = (e) => { e.preventDefault(); if (!previewSource) return; Axios.put(`api url`, { data: imageFile}); } return ( <div> <form onSubmit={handleSubmitFile}> <input type="file" onChange={handleFileInputChange} /> <button type="submit"> submit </button> </form > </div > ) }
ซึ่งก็เป็นโค้ดที่จะมีปุ่มเลือกไฟล์ แล้วก็ปุ่มอัปโหลดไฟล์นั้น หน้าตาปุ่มดังกล่าวก็ยังดูธรรมดา ๆ อย่างที่เห็น
นำ react-dropzone มาใช้กับโค้ดเดิมของเรา
ในส่วนของการนำ react-dropzone มาใช้มันก็มีอยู่ 2 วิธีตามเว็บไซต์ของ react-dropzone คือ เขียนแยกเป็นฟังก์ชัน กับ wrap เป็น component ไปเลย แต่ในที่นี้จะทำแบบแรกละกัน
โดยเมื่อนำโค้ดตัวอย่างจากบนเว็บไซต์มาใส่ในโค้ดของเรา แล้วก็ตกแต่งนิดหน่อยก็จะได้ออกมาหน้าตาตามนี้เลย
import React, { useState } from 'react'; import Axios from 'axios'; export default function Upload() { Axios.defaults.withCredentials = true; const [imageFile, setImageFile] = useState(''); const onDrop = useCallback((acceptedFiles) => { handleFileInputChange(acceptedFiles[0]); }, []); const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop, accepts: "image/*", multiple: false, }) const handleFileInputChange = (file) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onloadend = () => { setImageFile(reader.result); } } const handleSubmitFile = (e) => { e.preventDefault(); if (!imageFile) return; Axios.put(`api url`, { data: imageFile}); } return ( <div> <div {...getRootProps()}> <input {...getInputProps()} /> { isDragActive ? <p>Drop the files here ...</p> : <p>Drag 'n' drop some files here, or click to select files</p> } </div> <form onSubmit={handleSubmitFile}> <button type="submit"> submit </button> </form > </div > ) }
โอ้โห มันโซอีซี่ โดยภายใน onDrop เราก็จะใส่ function handleFileInputChange ที่เราเคยได้เขียนไว้เพื่อส่งข้อมูลไฟล์ที่เราลากมาวางไปที่ฟังก์ชันของเรา ส่วนใน useDropzone ตรงนี้เราได้เพิ่ม accepts: “image/*” เข้าไป ซึ่งเป็นการบอกว่าเราจะรับไฟล์ประเภทรูปภาพ และ multiple: false เพื่อบอกว่ามันอัปโหลดได้ทีละไฟล์ ส่วนใน handleFileInputChange เองก็มีการเปลี่ยนแปลงเล็กน้อย โดย prop ที่เรารับมาเราจะเปลี่ยนเป็น file โดยมันจะส่งตรงไปที่ reader.readAsDataURL ไปเลย แล้วก็ลบ const file = e.target.files[0]; ไปได้เลยเพราะไม่ต้องใช้แล้ว เนื่องจาก react-dropzone ได้จัดการให้เราเป็นที่เรียบร้อยแล้ว
ส่วน component ของเรา เราก็เอาโค้ดจากบนเว็บไซต์มาใส่เลยเช่นกัน แล้วก็ลบในส่วนของ input ไปได้เลย เนื่องจากเรามี react-dropzone มาแล้วเช่นกัน
โดยผลลัพธ์จากออกมาดังนี้
(หน้าตาตอนยังไม่ได้ลากไฟล์มา)
(หน้าตาตอนมีไฟล์ถูกลากมาบน)
ตกแต่งด้วย CSS
บนหน้าลากวางไฟล์ของเรามันอาจจะยังดูไม่สวยไม่ชัดเจนเท่าไร เรามาลองตกแต่งมันด้วย CSS กันดูหน่อยดีกว่า
.dropzone { height: 40vh; margin: 1rem; padding: 1rem; border: 2px dashed lightgrey; border-radius: 0.5rem; display: flex; justify-content: center; align-items: center; cursor: pointer; -webkit-transition: background-color 100ms linear; -ms-transition: background-color 100ms linear; transition: background-color 100ms linear; } .upload .active { background-color: whitesmoke; -webkit-transition: background-color 100ms linear; -ms-transition: background-color 100ms linear; transition: background-color 100ms linear; }
โดย CSS ของเราก็จะมีเพียง 2 ส่วนคือ .dropzone คือหน้าตาของ drop ในเวลาปกติ และ .upload กับ .active คือหน้าตาของ dropzone เวลามีไฟล์ถูกลากมา
และในส่วนของ component เราก็จะเป็นการนำ css เหล่านั้นมาใช้ดังนี้
<div className="upload" > <div {...getRootProps()} className={`dropzone ${isDragActive ? "active" : null}`} > <input {...getInputProps()} /> { isDragActive ? <p>Drop the files here ...</p> : <p>Drag 'n' drop some files here, or click to select files</p> } </div> <form onSubmit={handleSubmitFile}> <button type="submit"> submit </button> </form > </div >
ผลลัพธ์ที่ได้
ผลลัพธ์ที่ได้
สรุปสุดท้ายสิ่งที่ผู้อ่านจะได้รับ
เป็นยังไงกันบ้างครับสำหรับการใช้งาน react-dropzone เรียกได้ว่าง่ายสุด ๆ ไปเลยใช่ไหมครับ แต่สำหรับใครที่ยังต้องการตั้งค่าให้เหมาะกับงานของเรามากขึ้นเนี่ย มันยังมี PROPS กับ METHODS ให้ได้เล่นกันอีกมากมายเลย แล้วก็มีตัวอย่างแสดงวิธีการใช้งานที่ง่ายสุด ๆ สำหรับรายละเอียดเพื่อน ๆ ก็สามารถเข้าไปที่เว็บไซต์ https://react-dropzone.js.org/#src ได้เลย
อ้างอิงจาก
- Image Uploads to Cloudinary in React with Drag & Drop, สืบค้นเมื่อ 27 มกราคม 2565 จาก: https://www.youtube.com/watch?v=V8w7K1HdrFo&t=404s
-
react-dropzone, สืบค้นเมื่อ 4 กุมภาพันธ์ 2565 จาก: https://react-dropzone.js.org