Reputation: 88
I'm building a meme generator app. Here is my main component
const [inputText, setInputText] = useState<InputText[]>([
{ text: "", top: 30, left: 30 },
{ text: "", top: 45, left: 45 },
]);
//
//Drag'n'Drop functionality
//
const moveText = (
id: string,
left: number,
top: number,
children: string
) => {
setInputText(
inputText.map((textObj, i) =>
i === +id ? { text: children, top, left } : textObj
)
);
};
const [, drop] = useDrop(() => ({
accept: ItemTypes.MEME_TEXT,
drop: (item: DragItem, monitor) => {
const movementOf = monitor.getDifferenceFromInitialOffset() as XYCoord;
const left = Math.round(item.left + movementOf.x);
const top = Math.round(item.top + movementOf.y);
const { children } = item;
moveText(item.id, left, top, children);
return undefined;
},
collect: (monitor) => ({ isOver: !!monitor.isOver() }),
}));
return (<div
id="generatedMeme"
className="relative flex items-center justify-center"
>
{inputText.map((textObj, i) => (
<Text key={i} id={i} left={textObj.left} top={textObj.top}>
{textObj.text}
</Text>
))}
<img
ref={drop}
alt="meme-img"
src={currentMeme}
className="rounded-sm max-w-2xl min-w-"
/>
</div>)
When the <Text />
component gets dragged, and then dropped, every instance of this component disappears, apart from the one dragged. The inputFields array is reduced to a length of 2 (default state). Rerendering (by typing text in an input) the remaining hidden component reveals that it returned to its default position. Console logging revealed that
Here is the <Text />
component.
const Text = ({ children, id, left, top }: props) => {
const [, drag] = useDrag(
{
type: ItemTypes.MEME_TEXT,
item: { id, left, top, children },
},
[children, left, top]
);
return (
<div
ref={drag}
className="absolute text-white text-outline text-3xl font-meme uppercase"
style={{ top, left }}
>
{children}
</div>
);
};
I thought that maybe it's a weird case of the component not getting the props after moveText is fired, that's why I tried force passing it the children
prop, but that doesn't change anything. I'm at a loss as to what to even try.
Upvotes: 2
Views: 383
Reputation: 88
I didn't add a proper dependency array.
const [, drop] = useDrop(() => ({
accept: ItemTypes.MEME_TEXT,
drop: (item: DragItem, monitor) => {
const movementOf = monitor.getDifferenceFromInitialOffset() as XYCoord;
const left = Math.round(item.left + movementOf.x);
const top = Math.round(item.top + movementOf.y);
const { children } = item;
moveText(item.id, left, top, children);
return undefined;
},
collect: (monitor) => ({ isOver: !!monitor.isOver() }),
}), [inputText]);
and the same for useDrag, fixed everything. Turned out react-dnd takes memoization very seriously!
Upvotes: 2