monsterooo / blog

and make promises by the hours
MIT License
14 stars 1 forks source link

React DnD 预览 #36

Open monsterooo opened 5 years ago

monsterooo commented 5 years ago

React DnD GitHub - mzabriskie/react-draggable: React draggable component

预览

什么是项目(item)?项目(item)是一个简单的javascript对象,用于描述被拖动的内容。例如在看板应用程序中,当你拖动卡片是,项目可能看起来像{cardId: 42}。将拖动的数据描述为普通的对象有助于保持组件分离并且彼此不知道

DnD通过称为监视器(monitors)的内部状态存储上的几个小包装器将此状态公开给组件。监视器允许你更新组件的poprs以相应拖动状态更改。

假设你想在拖动棋子时突出显示象棋单元格。Cell组件的收集函数(collecting function)可能就像下面这样:

function collect(monitor) {
  return {
    highlighted: monitor.canDrop(),
    hovered: monitor.isOver(),
  }
}

它指示DnD将突出显示的最新值作为props传递给所有Cell实例

实际上,连接器(connectors)作为我们上面描述的收集函数的第一个参数传递。让我们来看看如何使用它来指定放置目标

// collect函数的第一个参数就是连接器
function collect(connect, monitor) {
  return {
    highlighted: monitor.canDrop(),
    hovered: monitor.isOver(),
    connectDropTarget: connect.dropTarget(),
  }
}

在组件render方法中,我们即可以访问从监视器(monitor)获得的数据和从连接器(connector)获得的函数:

render() {
  const { highlighted, hovered, connectDropTarget } = this.props;

  return connectDropTarget(
    <div className={classSet({
      'Cell': true,
      'Cell--highlighted': highlighted,
      'Cell--hovered': hovered
    })}>
      {this.props.children}
    </div>
  );
}

connectDropTarget调用告诉DnD我们的根DOM节点是一个有效的放置(drop)目标,并且它的hover和drop事件应该由后端处理。在内部,它通过将一个回调引用附加到你给它的React元素来工作。连接器返回的函数是memoized,因此它不会破坏shouldComponentUpdate优化。

高阶组件组件只是一个函数,它接收一个React组件,并返回另一个React组件类。库提供的包装组件在其render方法中呈现组将并将props转发给它,但也添加了一些有用的行为。

在DnD中,DragSourceDragTarget以及一些其他顶级导出函数实际上是高阶组件。它们向组件中注入拖放魔法。

使用它们的一个提示是,它们必须需要两个函数。例如,一下是如何在DragSource中包装YourComponent

import { DragSource } from 'react-dnd'

class YourComponent {
  /* ... */
}

export default DragSource(/* ... */)(YourComponent)

请注意,在第一个函数调用中指定DragSource参数之后,还有第二个函数调用,第二个函数调用中传递你的类(组件)。这叫做curryingpartial application,并且是装饰器语法开箱即用的必要条件:

import { DragSource } from 'react-dnd'

@DragSource(/* ... */)
export default class YourComponent {
  /* ... */
}

你不需要使用这种装饰器语法,如果你喜欢它,你可以使用Babel来转换你的代码,并将{ "stage": 1 }放入.babelrc文件来启用它。

即使你不打算使用装饰器,部分应用程序仍然可以使用,因为你可以使用如_.flow在javascript中组合多个DragSourceDropTarget声明。

import { DragSource, DropTarget } from 'react-dnd'
import flow from 'lodash/flow'

class YourComponent {
  render() {
    const { connectDragSource, connectDropTarget } = this.props
    return connectDragSource(
      connectDropTarget(),
      /* ... */
    )
  }
}

export default flow(
  DragSource(/* ... */),
  DropTarget(/* ... */),
)(YourComponent)

// Drag sources和drag targets只有在具有相同的字符串类型是才交互 const Types = { CARD: 'card', }

/**

/**

function Card(props) { // 你的组件可以像以前一样收到props const { id } = props

// 这两个props由DnD注入,由上面的collect函数定义 const { isDragging, connectDragSource } = props

return connectDragSource(

I am a draggable card number {id} {isDragging && ' (and I am being dragged now)'}
, ) } // 导出包装的版本 export default DragSource(Types.CARD, cardSource, collect)(Card) ``` 本章预览部分完。