Skip to content

Commit bd94d1c

Browse files
committed
feat: Enhance reaction handling with optimistic updates and toggle functionality
1 parent 15d366e commit bd94d1c

File tree

1 file changed

+61
-4
lines changed

1 file changed

+61
-4
lines changed

src/components/render-props/ReactionStatus.tsx

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ interface Props {
2020
}) => React.ReactNode;
2121
}
2222

23-
// All possible reactions
24-
2523
const ReactionStatus: React.FC<Props> = ({
2624
resource_id,
2725
resource_type,
@@ -42,7 +40,66 @@ const ReactionStatus: React.FC<Props> = ({
4240
resource_type,
4341
reaction_type,
4442
}),
45-
onSuccess: () => {
43+
onMutate: async (reaction_type: REACTION_TYPE) => {
44+
// Cancel any outgoing refetches
45+
await queryClient.cancelQueries({
46+
queryKey: ["reaction", resource_id, resource_type],
47+
});
48+
49+
// Snapshot the previous value
50+
const previousReactions = queryClient.getQueryData<ReactionStatusModel[]>(
51+
["reaction", resource_id, resource_type]
52+
);
53+
54+
// Optimistically update to the new value
55+
queryClient.setQueryData<ReactionStatusModel[]>(
56+
["reaction", resource_id, resource_type],
57+
(old = []) => {
58+
const existingReaction = old.find(
59+
(r) => r.reaction_type === reaction_type
60+
);
61+
62+
if (existingReaction) {
63+
// If reaction exists, toggle it (remove if active, or toggle status)
64+
if (existingReaction.is_reacted) {
65+
// Remove the reaction
66+
return old.filter((r) => r.reaction_type !== reaction_type);
67+
} else {
68+
// Activate the reaction
69+
return old.map((r) =>
70+
r.reaction_type === reaction_type
71+
? { ...r, is_active: true, count: r.count + 1 }
72+
: r
73+
);
74+
}
75+
} else {
76+
// Add new reaction
77+
return [
78+
...old,
79+
{
80+
reaction_type,
81+
is_reacted: true,
82+
count: 1,
83+
resource_id,
84+
resource_type,
85+
} as ReactionStatusModel,
86+
];
87+
}
88+
}
89+
);
90+
91+
// Return a context object with the snapshotted value
92+
return { previousReactions };
93+
},
94+
onError: (err, reaction_type, context) => {
95+
// If the mutation fails, use the context returned from onMutate to roll back
96+
queryClient.setQueryData(
97+
["reaction", resource_id, resource_type],
98+
context?.previousReactions
99+
);
100+
},
101+
onSettled: () => {
102+
// Always refetch after error or success to ensure we have the latest data
46103
queryClient.invalidateQueries({
47104
queryKey: ["reaction", resource_id, resource_type],
48105
});
@@ -54,7 +111,7 @@ const ReactionStatus: React.FC<Props> = ({
54111
};
55112

56113
const getReaction = (reaction_type: REACTION_TYPE) => {
57-
return query?.data?.find((r) => r.reaction_type == reaction_type);
114+
return query?.data?.find((r) => r.reaction_type === reaction_type);
58115
};
59116

60117
return render({

0 commit comments

Comments
 (0)