How to mutate complex object with nested array with SWR?

Viewed 1035

TL;DR:

How can I spread a new object inside a nested array e.g. data.posts.votes and also keep all the existing state from data

Full Info:

I have data I fetch that looks like that:

enter image description here

I want to have an upvote functionality that adds a new vote object into the votes array in the screenshot above.

​

I really have no plan right now how to do this in the mutate function from swr:

Right now I have it like this but that won't work:

mutate(
    `/api/subreddit/findSubreddit?name=${fullSub.name}`,
    (data) => {
      console.log(data);
      return {
        ...data,
        posts: (data.posts[postid].votes = [
          ...data.posts[postid].votes,
          { voteType: "UPVOTE" },
        ]),
      };
    },
    false
  );

How can I optimistically update this?

2 Answers

I think your approach should be like this:

mutate(
  `/api/subreddit/findSubreddit?name=${fullSub.name}`,
  async (data) => {
    console.log(data);
    return {
      ...data,
      posts: data.posts.map((post) => {
        if (post.id === postid) {
          return {
            ...post,
            votes: [...post.votes, { voteType: "UPVOTE" }],
          };
        } else {
          return post;
        }
      }),
    };
  },
  false
);

Try using immer

produce(data, draft => {
  const post = draft.posts.find( p => p.id === postId);
  post.votes.push(newVote);
})

All immutable without the clunky spreads.

Related