1

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 2

1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

You should use a deep copy of the object, spread operator creates only a shallow copy. Spread operator gives you deep copy normally (ES2015), React handles it differently?
Spread operator creates a deep copy only if the object is not nested. Here is a good blog
Ahh ok. I didn't think about the nested objects.
@SinanYaman Thank You very much! Great explanation and it works :)
1

I think you need something like this: copy of current issuesList state. Update the specific star from that copy of state. Set the updated state.

Here is a working sandbox example: https://codesandbox.io/s/bold-browser-cnfw3?file=/src/App.js

2 Comments

let updatedIssues = issuesList this line doesn't create a shallow copy. And since the object is nested, shallow copy won't quite cut it in this example
I edited my answer. Check out my sandbox. It is a working example of the data provided by author

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.