Update only one parameter when array is in array React

Viewed 222

I have state data like that:

const IssuesList = () => {
  const [issuesList, setIssuesList] = useState([
    {
      groupId: 0,
      groupData: "19-07-2016",
      groupIssues: [
        {
          id: 0,
          title: "Page changes",
          star: true,
        },
        {
          id: 1,
          title: "Review of last issues",
          star: true,
        },
      ],
    },
    {
      groupId: 1,
      groupData: "18-07-2016",
      groupIssues: [
        {
          id: 2,
          title: "Visual UI Update Review",
          star: false,
        },
        {
          id: 3,
          title: "Sidebar changes",
          star: false,
        },
      ],
    },
    {
      groupId: 2,
      groupData: "15-07-2016",
      groupIssues: [
        {
          id: 4,
          title: "Crash update",
          star: false,
        },
        {
          id: 5,
          title: "Page visual UI Update Review",
          star: true,
        },
        {
          id: 6,
          title: "Sidebar update",
          star: false,
        },
      ],
    },
    {
      groupId: 3,
      groupData: "14-07-2016",
      groupIssues: [
        {
          id: 7,
          title: "Crash issue",
          star: true,
        },
        {
          id: 8,
          title: "Visual update & Crash resolve",
          star: true,
        },
        {
          id: 9,
          title: "Header changes",
          star: false,
        },
      ],
    },
  ]);

  return (
    <div className="issuesList">
      {issuesList.map((group) => (
        <IssueGroup
          key={group.groupId}
          group={group}
          setIssuesList={setIssuesList}
          issuesList={issuesList}
        />
      ))}
    </div>
  );
};

export default IssuesList;

I want to change only the star parameter in groupIssues when I click an specyfic icon in a StarIcon component:

const StarIcon = ({ star, index, id, setIssuesList, issuesList, group }) => {
  const issueStar = group.groupIssues[index].star;

  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      //xmlns:xlink="http://www.w3.org/1999/xlink"
      preserveAspectRatio="xMidYMid"
      width="17"
      height="16"
      viewBox="0 0 17 16"
      className={star ? "staricon filled" : "staricon unfilled"}
      onClick={() => {
        // setIssuesList() TODO
      }}
    >
      <path
        d="M8.500,0.000 L11.301,5.028 L16.999,6.112 L13.033,10.302 L13.753,16.000 L8.500,13.561 L3.247,16.000 L3.967,10.302 L0.001,6.112 L5.699,5.028 L8.500,0.000"
        fill={star ? "#21233d" : "#fff"}
        stroke={star ? "none" : "#e0e0e0"}
      />
    </svg>
  );
};

export default StarIcon;

What is the best way to do that in that set of data. I know that spread operator can be helpfull there but i have no idea how to implement that in this data structure when We have array of objects and then we need to get into another array in specyfic object. Maybe changing the data structure will be better or breaking it into two arrays?

Ui view here

2 Answers

You should use a deep copy of the object, spread operator creates only a shallow copy.

Example:

const changeStar = (grpId, issueId) => {
 setIssuesList(list => (
   list.map(item => (
     item.groupId === grpId ? 
       {...item, groupIssues: item.groupIssues.map(issue => (
         issue.id === issueId ? {...issue, star: !issue.star} : issue
       ))}
     : item
   )
 ))
}

Explanation:

map function creates an entirely new array. It will return the elements as it is unless you have matching groupIds. Inside the groupIds, you will change the item based on the id. In the end, you deep copied the object and set an entirely new array with the desired result.

Related