reactjstypescriptreact-dnd

React Component becomes undefined after second drag and drop


When I drag and drop a Component into my Box and then try to drag and drop the element in another Box, that looks the same from the code. I get an error. How could I fix that? It should be possible to drag and drop the component in every box.

Here the Error:

ERROR Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check the render method of Box. Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Here the code:

import { FC, useState, createElement, memo } from 'react';
import { useDrop, useDrag, DragSourceMonitor } from 'react-dnd';
import { ItemTypes } from '../constants/ItemTypes';

const Box: FC<any> = ({ prop }) => {
    const [item, setItem] = useState<any>();
    const [, drop] = useDrop<any>(() => ({
        accept: ItemTypes.BOX,
        drop(itemDrag, monitor) {
            console.log(typeof(itemDrag));
            console.log(itemDrag)
            setItem(itemDrag);
        },
        collect: monitor => ({
            isOver: !!monitor.isOver(),
        }),
    }));
    const [{ isDragging }, drag] = useDrag(() => ({
        type: ItemTypes.BOX,
        item: { item: item },
        canDrag: item,
        collect: (monitor: DragSourceMonitor) => ({
            isDragging: !!monitor.isDragging(),
        })
    }));
    return (
        <div ref={drop} style={{ backgroundColor: "#FF0000" }}>
            {prop}
            {item && (
                <div ref={drag}>
                    {createElement(item.item)}
                </div>
                )}
        </div>
    );
};

export default memo(Box);

I found out, that the React Component becomes undefined while the second drop:

console.log in the drop function of useDrop hook:

First drop from Container:

Objectitem: () => {…}[[Prototype]]: Object

Second drop from Box:

Objectitem: undefined[[Prototype]]: Object

I found additional out, that if I use the useDrag within the component it self the issue is not there, only if I use my DragWrapper Component. But I want to use it, it will spare me copy and paste and will make it easer to change (but you know all that :-)) Additional here the code from the DragWrapper component:

import { ComponentType, FC, ReactNode, createElement } from 'react';
import { useDrag, DragSourceMonitor } from 'react-dnd';
import { ItemTypes } from '../constants/ItemTypes';

interface DragWrapperType {
    child: ComponentType<any>
    props?: Object
}

const DragWrapper: FC<DragWrapperType> = ({ child, props }) => {
    const [{ isDragging }, drag] = useDrag(() => ({
        type: ItemTypes.BOX,
        item: { item: child },
        collect: (monitor: DragSourceMonitor) => ({
            isDragging: !!monitor.isDragging(),
        })
    }))
    return (
        <div ref={drag}>
            {child && createElement(child, props)}
        </div>
    );
};

export default DragWrapper;

Solution

  • So issue solved.

    It seems like the Object was undefined, because it was from the beginning undefined. I guess the useDrag hook was at the beginning initialized and never changed throw the useStat hook.

    To solve the issue I just had to get sure, the useDrag hook initialize when there is a defined object, I used the DragWrapper for that:

    {item && item.item &&(
         <DragWrapper child={item.item} />
    )}