Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to attach drag event handlers to a React component using TypeScript

I'm making my first foray into React (15.6.1) with TypeScript (2.4.2), and I'm trying to create a component that represents a JSON field which is draggable. Here is my component code:

import * as React from "react";

interface JsonFieldProps {
    name: string;
    type: string;
    indent: number;
}

export class JsonField extends React.Component<JsonFieldProps, undefined> {
    marginStyle = {
        'text-indent': `${this.props.indent * 15}px`
    };

    render() {
        return <div draggable={true} onDragStart={handleDrag} style={this.marginStyle}>{this.props.name}: {this.props.type},</div>;
    }
}

function handleDrag(ev: DragEvent): void {
    let id = (ev.target as HTMLDivElement).id;
    ev.dataTransfer.setData("text/plain", id);
}

When I try to compile it (using webpack), I get the following error:

ERROR in [at-loader] ./src/components/JsonField.tsx:15:21 
  TS2322: Type '{ draggable: true; onDragStart: (ev: DragEvent) => void;
    style: { 'text-indent': string; }; child...' is not assignable to type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'.
  Type '{ draggable: true; onDragStart: (ev: DragEvent) => void; style: { 'text-indent': string; }; child...' is not assignable to type 'HTMLAttributes<HTMLDivElement>'.
    Types of property 'onDragStart' are incompatible.
      Type '(ev: DragEvent) => void' is not assignable to type 'EventHandler<DragEvent<HTMLDivElement>>'.
        Types of parameters 'ev' and 'event' are incompatible.
          Type 'DragEvent<HTMLDivElement>' is not assignable to type 'DragEvent'.
            Property 'initDragEvent' is missing in type 'DragEvent<HTMLDivElement>'.

I'm not sure if I'm using the wrong event type, but I can't seem to find any info about which one is correct if it is wrong.

like image 231
Jared Avatar asked Sep 05 '17 21:09

Jared


1 Answers

You must use React.DragEvent interface instead of generic DOM DragEvent:

export class JsonField extends React.Component<JsonFieldProps, undefined>
{
    private marginStyle = {
        textIndent: `${this.props.indent * 15}px`
    };

    public render()
    {
        return (
            <div
                draggable={true}
                onDragStart={handleDrag}
                style={this.marginStyle}>
                {this.props.name}: {this.props.type}
            </div>);
    }
}

function handleDrag(ev: React.DragEvent<HTMLDivElement>): void
{
    const id = (ev.target as HTMLDivElement).id;
    ev.dataTransfer.setData("text/plain", id);
}

Note also change of text-indent to textIndent as you are using react and not pure html. Remember in react you are mainly working with virtual DOM, not real one - therefore all these changes.

As a side note I would recommend you to keep event handlers within class and not outside of it. This way you will be able to access class instance properties and methods.

like image 83
Amid Avatar answered Oct 23 '22 09:10

Amid