Reputation: 1327
The title might be a little bit ambigous, but I'll explain better :)
So I have this component DraggableGameSlots.tsx
import React, { useState } from "react";
import DraggableGameSlot from "./DraggableGameSlot";
type DraggableGameSlotsProps = {
numberOfAnswers: number,
slotFor: string
}
function DraggableGameSlots(props: DraggableGameSlotsProps) {
const [answers, setAnswers] = useState<string[]>(Array<string>(props.numberOfAnswers).fill("Drop here"));
return (
<div className="draggable-game-slots">
{
answers.map((val, index) => (
<DraggableGameSlot
className={props.slotFor === "text" ? "draggable-game-slot-for-text" : "draggable-game-slot-for-image"}
key={index}
answers={answers}
setAnswers={setAnswers}
/>
))
}
</div>
);
}
export default DraggableGameSlots;
and DraggableGameSlot.tsx
import { useEffect, useRef } from 'react';
import { useDrop } from 'react-dnd';
import './css/DraggableGameSlot.css';
type DraggableGameSlotProps = {
className: string,
answers: any,
setAnswers: any
}
function DraggableGameSlot(props: DraggableGameSlotProps) {
const [{isOver}, drop] = useDrop(() => ({
accept: "image",
drop(item: {id: string}) {
props.setAnswers([...props.answers, item.id]);
console.log(props.answers);
},
collect: (monitor) => ({
isOver: !!monitor.isOver(),
})
}))
useEffect(() =>
console.log(props.answers)
);
return (
<div className={`draggable-game-slot ${props.className}`} ref={drop}>
<span>Drop here</span>
</div>
)
}
export default DraggableGameSlot;
The logic is as follows:
I have an array of answers and I want to add new answers using react-dnd. The initial answers are "Drop here" (because they are not defined, only the slots with this text will appear - I'll implement this logic later).
So I have an array which contains all of the answers. I render them and everything is fine.
Then I have an useDrop hook from react-dnd - it is used to define the drop target for the draggable items. That is not the point of the posts either :)
I observed using the two console.logs from DraggableGameSlot, that for numberOfAnswers = 4, my array will be either length = 4 (initially) or length = 5, when I drop an answer and drop is called.
I expected each time an answer is dropped and props.setAnswers is called, a new answer will be added at the end of the array. Well, it doesn't work like this, actually, the 5th item is changed everytime.
e.g.
Drop here Drop here Drop here Drop here
I drag answer1:
Expectation: Drop here Drop here Drop here Drop here answer1
Behavior: Drop here Drop here Drop here Drop here answer1
OK
I drag answer2:
Expectation: Drop here Drop here Drop here Drop here answer1 answer2
Behavior: Drop here Drop here Drop here Drop here answer2
NOT OK
I suspect that it happens because props.answers doesn't update. I probably get a copy of its value when passing it through props, not a reference, so when I call setAnswers the answers array is updated only in DraggableGameSlots and props.answers stay the same.
Well, I don't want that.
Why is this happening and how can I make it work the way I intend? :)
Upvotes: 1
Views: 224