ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

React DnD 官方指南:用 useDrag 构建解耦的拖拽交互(docsRoot 门户文档全解析)

React DnD 官方指南:用 useDrag 构建解耦的拖拽交互(docsRoot 门户文档全解析) React DnD 官方指南用 useDrag 构建解耦的拖拽交互docsRoot 门户文档全解析【免费下载链接】react-dndDrag and Drop for React项目地址: https://gitcode.com/gh_mirrors/re/react-dnd本篇技术指南基于当前仓库中 packages/docsite/markdown/docs/docsRoot.md 门户文档展开全面讲解 React DnDDrag and Drop for React的定位、安装方式、Hooks 风格的拖拽用法以及它解耦组件、拥抱单向数据流、屏蔽浏览器差异、支持自定义后端的核心设计理念。读完本文你将掌握如何用react-dndreact-dnd-html5-backend在十分钟内让任意组件变成可拖拽的拖拽源理解 Drag Source、Drop Target、Monitor、Connector、Backend 五大抽象之间的关系并了解如何通过模拟后端在 Node 环境中测试拖拽交互。React DnD 是什么React DnD 是一组 React 工具库帮助你构建复杂的拖拽交互界面同时保持组件之间的解耦decoupled。它非常适合 Trello、Storify 这类应用场景拖拽在应用的不同部分之间传递数据组件外观与应用状态会随拖拽事件实时变化。它不是一个开箱即用的拖拽组件库而是一套构建拖拽能力的原语primitives它不替你画任何 UI而是把你的组件包装起来向组件注入 props 和 refs由你的组件来决定拖拽时看起来是什么样。安装与后端选型安装react-dnd时通常需要同时安装一个后端backendnpm install react-dnd react-dnd-html5-backend其中react-dnd是核心库提供DndProvider、useDrag、useDrop、useDragLayer等 APIreact-dnd-html5-backend在底层使用 HTML5 拖拽 API 处理真实的浏览器拖拽事件。你完全可以换用第三方后端例如针对触屏设备的react-dnd-touch-backend当前仓库中的实现位于 packages/backend-touch/src/index.ts其触屏实现细节见 TouchBackendImpl.ts。HTML5 后端与 Touch 后端的详细说明分别见 HTML5.md 与 Touch.md。从源码看后端是什么在 packages/backend-html5/src/index.ts 中可以看到HTML5 后端本质上是一个BackendFactoryexport const HTML5Backend: BackendFactory function createBackend( manager: DragDropManager, context?: HTML5BackendContext, options?: HTML5BackendOptions, ): HTML5BackendImpl { return new HTML5BackendImpl(manager, context, options) }而 packages/dnd-core/src/interfaces.ts 定义了后端需要实现的契约setup()、teardown()、connectDragSource()、connectDragPreview()、connectDropTarget()。后端只做一件事——把原生 DOM 事件翻译成 React DnD 内部可处理的 Redux action这一点下文会展开。快速上手让一个组件变得可拖拽官方文档用一段简洁示例展示了useDragHook 的用法——把Card textWrite the docs /变成可拖拽组件import React from react import { useDrag } from react-dnd import { ItemTypes } from ./Constants /** * Your Component */ export default function Card({ isDragging, text }) { const [{ opacity }, dragRef] useDrag( () ({ type: ItemTypes.CARD, item: { text }, collect: (monitor) ({ opacity: monitor.isDragging() ? 0.5 : 1 }) }), [] ) return ( div ref{dragRef} style{{ opacity }} {text} /div ) }这段代码的关键点type拖拽源的类型标识字符串或 symbol只有注册了相同类型的 drop target 才会对它做出反应item描述被拖拽数据的纯 JavaScript 对象这里只有{ text }这是 drop target 能获得的唯一信息来源所以应当只放最小必要数据collect(monitor)收集函数从 monitor 中取出isDragging()状态并合成为组件 props返回值数组[0]是收集到的 props[1]是拖拽源 refdragRef必须挂到可拖拽的 DOM 节点上。从源码看 useDrag 的实现在 packages/react-dnd/src/hooks/useDrag/useDrag.ts 中useDrag的返回结构一目了然export function useDragDragObject, DropResult, CollectedProps( specArg, deps?, ): [CollectedProps, ConnectDragSource, ConnectDragPreview] { const spec useOptionalFactory(specArg, deps) invariant(!(spec as any).begin, useDrag::spec.begin was deprecated in v14. Replace spec.begin() with spec.item(). ...) const monitor useDragSourceMonitorDragObject, DropResult() const connector useDragSourceConnector(spec.options, spec.previewOptions) useRegisteredDragSource(spec, monitor, connector) return [ useCollectedProps(spec.collect, monitor, connector), useConnectDragSource(connector), useConnectDragPreview(connector), ] }值得注意的实现细节spec 可以是对象也可以是工厂函数useOptionalFactory会结合deps做记忆化官方推荐函数形式因为它能闭包读取最新 propsv14 起spec.begin已废弃必须改用spec.item源码中的invariant断言会在误用时抛出明确错误见 useDrag.ts返回的第二个元素是ConnectDragSource拖拽源 ref第三个是ConnectDragPreview拖拽预览 ref分别对应后端契约中的connectDragSource与connectDragPreview。对应地放置目标的useDrop返回[CollectedProps, ConnectDropTarget]见 packages/react-dnd/src/hooks/useDrop/useDrop.ts。别忘了 DndProvider使用这些 Hooks 之前需要用DndProvider在组件树根部注入 DnD 上下文例如配合 HTML5 后端import { DndProvider } from react-dnd import { HTML5Backend } from react-dnd-html5-backend DndProvider backend{HTML5Backend} Card textWrite the docs / /DndProviderDndProvider的实现见 packages/react-dnd/src/core/DndProvider.tsx它接收backend工厂函数与可选的options、debugMode内部调用createDragDropManager创建管理器再通过DndContext.Provider向下层组件提供若未传入context管理器会以全局单例形式缓存__REACT_DND_CONTEXT_INSTANCE__符号组件卸载时通过 refCount 清理避免内存泄漏。createDragDropManager的底层逻辑在 packages/dnd-core/src/createDragDropManager.ts它创建一个 Redux storedebugMode为 true 且存在 Redux DevTools 扩展时自动接入见 createDragDropManager.ts再构建 Monitor、HandlerRegistry、Manager最后由backendFactory(manager, globalContext, backendOptions)实例化后端并注入。React DnD 本身就是构建在 Redux 之上的。四大设计特性Features官方文档总结了 React DnD 的四个核心特性结合源码可以看得更深1. 与你的组件协作而非提供现成组件React DnD 不提供 readymade 组件而是包装你的组件并注入 props——如果你用过 React Router 或 Flummox对这种模式应该不陌生。useDrag返回的[collectedProps, dragRef, dragPreviewRef]就是这种注入的具体形态collected props 由你决定refs 由你决定挂到哪里框架只负责在恰当的时机更新它们。2. 拥抱单向数据流React DnD 完全遵循 React 的声明式渲染范式不直接修改 DOM与 Redux 以及其它单向数据流架构天然互补——事实上它本身就是构建在 Redux 之上的。从源码结构可以印证这一点packages/dnd-core/src/reducers/ 下有一组纯 reducerdragOffset.ts、dragOperation.ts、dirtyHandlerIds.ts、refCount.ts、stateId.tspackages/dnd-core/src/actions/dragDrop/ 下是标准的 Redux action creatorsbeginDrag、hover、drop、endDrag、publishDragSource。所有的拖拽状态——是否正在拖拽、当前 item、指针偏移量、drop 结果——都保存在这个 Redux store 中由 reducer 纯函数驱动更新。组件通过 Monitor 订阅这些状态变化并重新收集 props形成完整的单向数据流闭环。3. 隐藏平台怪癖HTML5 拖拽 API 充满坑和浏览器不一致性React DnD 在内部处理它们让你专注于业务开发。例如HTML5 后端会自动对拖拽中的 DOM 节点截图作为拖拽预览你不用自己绘制跟随光标的内容后端抽象了浏览器差异其角色类似 React 的合成事件系统但不依赖 React 或 React 的合成事件系统见 packages/dnd-core/src/interfaces.ts 中后端接口与 React 无任何耦合。4. 可扩展、可测试React DnD 默认使用 HTML5 后端但允许你注入自定义后端可以基于触摸事件、鼠标事件或者完全自定义。例如内置的模拟后端react-dnd-test-backend见 packages/backend-test/src/TestBackend.ts可以让你在Node 环境中测试组件的拖拽交互——这正是 examples 下大量集成测试如 single-target-integration.spec.tsx、dragSources.spec.tsx赖以运行的基础。核心概念速览源自 Overview 的延伸docsRoot.md是文档门户其内容与 00 Quick Start/Overview.md 一脉相承。理解以下五个概念就能看懂整个文档体系Item 与 Type拖拽的不是 DOM 节点而是某种类型的 item——一个描述被拖拽数据的纯对象如{ cardId: 42 }。Type 是字符串或 symbol用于声明拖拽源与放置目标的兼容性Monitor拖拽是天然有状态的Monitor 是对内部状态存储的轻量封装让你能响应状态变化更新组件 propsConnector把拖拽源 / 拖拽预览 / 放置目标三种角色赋予具体 DOM 节点的函数内部通过 callback ref 附加事件且返回的函数是记忆化的不会破坏shouldComponentUpdate优化Drag Source 与 Drop Target把类型、item、副作用和收集函数与组件绑定起来的主要抽象单元drop target 可以同时注册多个类型Backend把 DOM 事件翻译为内部 Redux action 的可插拔实现。现代推荐用 Hooks APIuseDrag、useDrop、useDragLayer、useDragDropManager其完整讲解见 HooksOverview.md、useDrag.md 与 useDrop.mdHooks 的完整导出见 packages/react-dnd/src/hooks/index.ts。触屏支持Touch SupportHTML5 拖拽 API 在触屏设备上不工作。如需触屏支持请将react-dnd-html5-backend换成 touch backend即使用 packages/backend-touchnpm install react-dnd react-dnd-touch-backendimport { DndProvider } from react-dnd import { TouchBackend } from react-dnd-touch-backend DndProvider backend{TouchBackend} options{{ enableMouseEvents: true }} ... /DndProvider触屏后端的配置选项如enableMouseEvents、delay、delayTouchStart等在 packages/backend-touch/src/interfaces.ts 中定义并有对应的单元测试覆盖见 TouchBackend.spec.ts 与 OptionsReader.spec.ts。Non-Goals明确不做的事React DnD 提供一组强大的原语但不包含任何现成组件。它比 jQuery UI 或 interact.js 更底层聚焦于把拖拽交互做对而把视觉呈现如轴向约束、吸附网格留给你自己实现。一个典型的例子React DnD不计划提供Sortable组件而是给你构建自己 Sortable 所需的工具——排序场景的完整可运行示例见 examples/src/04-sortable/其中 simple 与 stress-test 展示了如何基于useDraguseDrop组合出排序能力拖拽吸附网格的工具函数示例见 snapToGrid.ts。支持、致谢与许可支持与贡献Issues 与改进建议的讨论渠道见仓库的 CODEOWNERS、CONTRIBUTING.md 与 CODE_OF_CONDUCT.md完整变更历史记录在 CHANGELOG.md致谢官方感谢 BrowserStack 为维护者提供浏览器问题调试服务许可React DnD 以MIT协议开源见 LICENSE可自由使用。下一步阅读路径门户文档为读者规划了清晰的进阶路线先读 00 Quick Start/Overview.md建立 Item/Type、Monitor、Connector、Source/Target、Backend 五大概念再读 03 Using Hooks/HooksOverview.md 熟悉 Hooks API 全貌动手实现 00 Quick Start/Tutorial.md 中的国际象棋教程配套完整示例在 examples/src/00-chessboard/按需查阅 useDrag.md、useDrop.md、useDragLayer.md 的规范细节以及 DndProvider.md 的上下文配置说明后端选型参考 05 Backends/HTML5.md 与 05 Backends/Touch.md测试方法参考 00 Quick Start/Testing.md配合react-dnd-test-backend在 Node 中完成拖拽交互测试。【免费下载链接】react-dndDrag and Drop for React项目地址: https://gitcode.com/gh_mirrors/re/react-dnd创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表