Крошечный рецепт приготовления react-dnd

—

от автора

Появилась однажды задача — сделать область для загрузки файлов, с помощью drag-and-drop.

Была выбрана библиотека react-dnd, по причине её простоты, минималистичности и низкого порога входа.

Фича реализуется с помощью это либы и двух кастомных компонентов:

  • DndContainer — компонент обёртка, для того, чтобы прокидывать вниз контекст для работы react-dnd

  • DropTarget — компонент для непосредственной реализации drag-and-drop функционала

Итак, рецепт!

react-dnd

Просто ставим её в зависимости и идём дальше.

DndContainer

Объявляем провайдер и пробрасываем в children наш будущий компонент DropTarget.

import React from 'react';  import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend';  import DropTarget from '../drop-target';  const DndContainer = (props: {   onDrop: (files: File[]) => void;   disabled: boolean;   title?: string;   hoverTitle?: string; }) => {   const {     onDrop,     disabled,     title = 'Перетащите сюда файлы',     hoverTitle = 'Отпустите для загрузки',   } = props;    return (     <DndProvider backend={HTML5Backend}>       <DropTarget         onDrop={onDrop}         disabled={disabled}         title={title}         hoverTitle={hoverTitle}       />     </DndProvider>   ); };  export default DndContainer; 

DropTarget

Компонент для реализации drag-and-drop функционала

import React from 'react';  import { useDrop } from 'react-dnd'; import { NativeTypes } from 'react-dnd-html5-backend';  import Styles from './index.css';  const DropTarget = (props: {   onDrop: (files: File[]) => void;   disabled: boolean;   title: string;   hoverTitle: string; }) => {   const { onDrop, disabled, title, hoverTitle } = props;   const [{ canDrop, isOver }, drop] = useDrop(     () => ({       accept: [NativeTypes.FILE],       drop: (item: { files: File[] }) => {         onDrop(item.files);       },       canDrop: () => !disabled,       collect: (monitor) => ({         isOver: monitor.isOver(),         canDrop: monitor.canDrop(),       }),     }),     [onDrop]   );   const isActive = canDrop && isOver;    return (     <div ref={drop} className={Styles.wrapper} data-disabled={disabled}>       <div className={Styles.dropTarget} data-active={isActive}>         {isActive ? hoverTitle : title}       </div>     </div>   ); };  export default DropTarget; 

Стили кастомные, но для примера оставлю:

.wrapper {   position: relative; } .wrapper[data-disabled='true'] {   cursor: not-allowed; } .wrapper[data-disabled='true']::after {   content: '';   position: absolute;   top: 0;   left: 0;   bottom: 0;   right: 0;   background-color: rgba(255, 255, 255, 0.35); }  .dropTarget {   display: flex;   justify-content: center;   align-items: center;   padding: 40px 20px;   margin: 20px 0;   border: 1px dashed black;   border-radius: 5px;   user-select: none;   color: black; }  .dropTarget[data-active='true'] {   border: 1px dashed #0022f5;   color: #0022f5; } 

Применение

Используем как совершенно обычный компонент:

type Props = {   handleFilesDrop: (files: File[]) => void;   title?: string; } const DnD = (props: Props) => {   const { handleFilesDrop, title = 'Перетащите сюда медиафайлы' } = props;    const shouldBeDisabled = /* some condition, based on state/props or whatever you need */;    return (     <div className={Styles.dnd}>       <DndContainer         title={title}         onDrop={handleFilesDrop}         disabled={shouldBeDisabled}       />     </div>   ); }; 

Итого

Выводов не планировалось, это просто минималистичный рецептик приготовления для быстрого сетапа функционала dnd в приложении))

Спасибо за чтение и удачи в реализации ваших dnd фич)

PS: ссылки из статьи


ссылка на оригинал статьи https://habr.com/ru/articles/732742/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *