skip to Main Content

I have a backend in node.js, where I generate this array –

let allItems = Array.from({ length: 1_000_000 }, (_, index) => ({
  id: index + 1,
  title: `Title ${index + 1}`,
  isSelected: false,
}));

On frontend I use react and dnd-kit to sort objects through drag and drop and I can also search by title.

Whole process and bug is displayed on pictures:enter image description here

enter image description here
enter image description here

enter image description here
enter image description here

After I typed in a string to search by,
selected by double tapping and dnd,
cleared my search, that array on backend changes to a new array where the first elements are search results, but it should be relative to search results, kind of like this –
if I dragged object 33 before object 3, it should be between object 2 and object 3.

This is a handler that sorts this array and saves to backend one –

app.put('/items', (req, res) => {
  const items = req.body.items;

  const updatedIds = new Set(items.map((item) => item.id));

  const updatedItems = items.map((updatedItem) => {
    const existingItem = allItems.find((item) => item.id === updatedItem.id);
    return {
      ...existingItem,
      ...updatedItem,
    };
  });

  const remainingItems = allItems.filter((item) => !updatedIds.has(item.id));

  const mergedItems = [...remainingItems];

  for (const updatedItem of updatedItems) {
    const index = items.findIndex((item) => item.id === updatedItem.id);
    if (index !== -1) {
      mergedItems.splice(index, 0, updatedItem);
    }
  }

  allItems = mergedItems;
  res.status(200).send({
    message: 'Items updated successfully'
  });
});

Pls, I worked on this problem for 2 days and I finally decided to ask here

2

Answers


  1. Chosen as BEST ANSWER

    What I did is I shifted the updating and reordering logic on backend, so my frontend would send only edited item, not the whole state of items.

    And based on the nearest right item id I update position of changed item on backend


  2. This is hard to follow given the problem is so abstract, and how many different copies of arrays there are. And zero typing because that’s Javascript for ya. But it seems like this is your mistake is in here:

        for (const updatedItem of updatedItems) {
            const index = items.findIndex((item) => item.id === updatedItem.id);
            if (index !== -1) {
                mergedItems.splice(index, 0, updatedItem);
            }
        }
    

    This expression:

    items.findIndex((item) => item.id === updatedItem.id)
    

    So from the original set of modified items you are finding the index of that item. Well hopefully you are sending some subset of items in an array to the backend, and not the full 1 million. If that’s the case there’s no possible way items’ index will correspond to the index in allItems array. Or the mergedItems array. It’s probably finding the 0th index for the first item, and sticking it at the front when it calls splice on mergedItems. Viola bug.

    I think you’ll have to modify what you send to the server so you communicate the index you want these updates to be at. So swapping item 33 so it’s before id 3. You’d need to send the index you want item 33 to be at. Something like this:

    {
       "fromIndex": 32,
       "toIndex": 2,
       "id": 33
    }
    

    Then things are a lot simpler to write that code, and you don’t need to do a bunch of find, findIndex, copy arrays around, yada yada.

    But, just so you are aware. You are modifying in memory data structures at a global level so therefore you’ll have concurrency issues out the yazoo if you multiple clients were operating on this data. Client 1 could upset Client 2 because of dead reckoning.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search