0

I have the following problem I can't seem to be able to figure out.

Container.jsx

 const [selectedCardTypeList, setSelectedCardTypeList] = useState([]); const onDragEnd = result => { const {destination, source, draggableId} = result; if (!destination) { return; } if (destination.droppableId === source.droppableId && destination.index === source.index ) { return; } let newInputIds = inputs; newInputIds.splice(source.index, 1); newInputIds.splice(destination.index, 0, draggableId); setSelectedCardTypeList(newInputIds); }; return ( <div> <DragDropContext onDragEnd={onDragEnd}> <DroppableWrapper selectedCardTypeList={selectedCardTypeList}> {selectedCardTypeList.map((v, index) => <CardContainer removeCardType={removeCardType} cardType={v} index={index}/> )} </DroppableWrapper> </DragDropContext> </div> ) 

DropableWrapper.jsx

import {Droppable} from "react-beautiful-dnd"; import React from "react"; export const DroppableWrapper = ({children, selectedCardTypeList}) => { return ( <> <Droppable droppableId="droppable" direction="horizontal"> {(provided, snapshot) => ( <div className={selectedCardTypeList.length ? 'container-horizontal' : 'container-vertical'} ref={provided.innerRef} {...provided.droppableProps} > {children} {provided.placeholder} </div> )} </Droppable> </> )}; export default DroppableWrapper; 

As you can see I omitted quite a lot of the code, and this is a dummy example but basically what is happening is if I declaratively pass in the children to the parent (using .map), the Child elements will only respect the first state change and despite I can confirm on action the state is being updated, this is not being reflected when rendering {children}.

Any ideas? Thank you!

There is nothing wrong with CardContainer, If I don't abstract the Droppable out as a wrapper just leave it with the container it works.

16
  • 2
    show us where you update the state Commented Apr 8, 2020 at 12:52
  • The useState hook can't "see" if the contents of an array have changed. You should use the useReducer hook instead. Commented Apr 8, 2020 at 12:54
  • So I omitted quite a lot of code, I am using react beautiful DnD and the state is updated in the onDragEnd prop. I can confirm the state is being updated correctly, I console.log-ed it out and inspected with the React extension. If I move the mapping to the child component, everything works fine, so I can only assume it's a React specific problem I am facing when dynamically passing down props.children. Commented Apr 8, 2020 at 12:55
  • Every component created by the map function must have a unique key, this is how React tracks the changes, try to add key={index} to your Child tag inside the map call Commented Apr 8, 2020 at 12:58
  • @HermitCrab thanks for your input, I am afraid that was the first thing I tried, but no joy. Commented Apr 8, 2020 at 12:58

1 Answer 1

2

You need to set the state with a function instead. At the end of onDragEnd:

 setSelectedCardTypeList(prevState => { var newState = [...prevState.slice(0, source.index), ...prevState.slice(source.index + 1)]; return [...newState(0, destination.index), draggableId, ...newState(destination.index)]; }); 
Sign up to request clarification or add additional context in comments.

2 Comments

I set the new state with a function like: setSelectedCardTypeList(() => { return [...newInputIds]; }); ...and it worked. Can you please give me context is because of asynchronous operation?
reactjs.org/docs/… You assigned inputs to newInputIds, then modified it. I would guess that react still sees it as the same value.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.