Reputation: 5204
I cannot figure out what is wrong with this code. I'm trying to write a simple wrapper component for the reactDND DragSource
HOC. The goal is to be able to write this:
const CanDrag = () => (
<Draggable type='FOO' source={{id: 1}} collector = {() => ({})} >
<div>whatever</div>
</Draggable>
);
rather than having to write
DragSource(type, source, collector)(CanDrag);
For my particular use case the former is more convenient. Here is the wrapper Component I have written:
import { DragSource } from 'react-dnd';
import { Component, Fragment } from 'react';
// A component that wraps its children in a draggable HOC
export default class Draggable extends Component {
DraggableItem = null;
static propTypes = {
type: propTypes.string.isRequired,
source: propTypes.object.isRequired,
collector: propTypes.func.isRequired,
children: propTypes.oneOf([
propTypes.node,
propTypes.element,
arrayOf([
propTypes.oneOf([
propTypes.node,
propTypes.element,
]),
]),
]),
};
componentWillMount() {
const {
type,
source,
collector,
children,
} = this.props;
this.DraggableItem = DragSource(type, source, collector)(<Fragment>{ children }</Fragment>);
}
render() {
const { DraggableItem } = this;
return <DraggableItem />;
}
}
I keep getting this error:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
Upvotes: 0
Views: 737
Reputation: 16354
The DragSource
HOC expects a component or function but you passed a rendered node <Fragment>{ children }</Fragment>
which is an object and not a component.
It's also not useful to do that at all as the component that gets wrapped needs to implement a certain interface. So you can't just pass arbitrary components to it as they will not consume the props injected by the HOC.
What you could do it to transform the HOC to a component that takes a render prop as the only child:
const Draggable = ({ type, spec, collect, children }) => {
const Source = DragSource(type, spec, collect)(
({ connectDragSource, isDragging }) => connectDragSource ? connectDragSource(children({ isDragging })) : children({ isDragging })
);
return <Source />
}
Then you could use it like this:
<Draggable type='FOO' source={{id: 1}} collector = {() => ({})} >
{({isDragging}) => (
<div>
{isDragging ? <p>Dragging...</p> : <p>Not Dragging...</p>}
</div>
)}
</Draggable>
Upvotes: 2