skip to Main Content

I want to duplicate an item with splice but I got problems while changing id. I need different ID for each items but while duplicate, it keeps the same id. Also the id become a number but should be a string.

const duplicateCard = (index, listId) => {
    const list = data.lists[listId];
    const duplicate_item = list.cards[index];
    duplicate_item["id"] = list.cards.length + 1;
    list.cards.splice(0, 0, duplicate_item);
    const newState = {
      ...data,
      lists: {
        ...data.lists,
        [listId]: list,
      },
    };
    setData(newState);
    window.localStorage.setItem("datt", JSON.stringify(newState));
  };

Output: The item is duplicated but id is changed for both same items and it becomes integer instead of string

2

Answers


  1. Chosen as BEST ANSWER

    As @cmgchess suggests, this is working:

    const duplicateCard = (index, listId) => {
        const list = data.lists[listId];
        const duplicate_item = {...list.cards[index]};
        duplicate_item["id"] = (list.cards.length + 1).toString();
        list.cards.splice(0, 0, duplicate_item);
        const newState = {
          ...data,
          lists: {
            ...data.lists,
            [listId]: list,
          },
        };
        setData(newState);
        window.localStorage.setItem("datt", JSON.stringify(newState));
      };
    

  2. splice is a mutable action. In React, you always construct new data –

    const duplicateCard = (index, listId) => {
      setData(data => {
        const list = data.lists[listId]
        return {
          ...data,
          lists: {
            ...data.lists,
            [listId]: {
              ...list,
              cards: [
                {
                  ...list.cards.at(index),
                  id: list.cards.length // you need better id generator
                },
                ...list.cards,
              ]
            },
        },
      })
    }
    

    Quite a state nightmare you’ve created for yourself!

    You could try to manage it with generic function like update

    function update(key, func) {
      return t => { switch (t.constructor) {
        case Array:
          return [...t.slice(0, key), func(t.at(key), key, t), ...t.slice(key + 1)]
        case Object:
          return {...t, [key]: func(t[key], key, t)}
        default:
          throw Error(`update called on non-object: ${t}`)
      }}
    }
    

    Now your duplicateCard function can be improved. Note newId is a responsibility of the caller –

    const duplicateCard = (index, listId, newId) => {
      setData(
        update("lists",
          update(listId,
            update("cards", cards => [
              { ...cards.at(index), id: newId },
              ...cards,
            ])
          )
        )
      )
    }
    

    It’s a big step in the right direction, and maybe you can see a pattern emerging. Still it seems like a lot of effort.

    It turns out immutable data structures have well-designed and tested tools to work with them. See libraries like ImmutableJS.

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