Skip to content

Commit 70d31ac

Browse files
committed
feat: Add useImmer for managing reaction state and optimize reaction toggle logic
1 parent bd94d1c commit 70d31ac

File tree

2 files changed

+53
-43
lines changed

2 files changed

+53
-43
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"date-fns": "^4.1.0",
4444
"dotenv": "^16.4.7",
4545
"drizzle-orm": "^0.41.0",
46+
"immer": "^10.1.1",
4647
"jotai": "^2.12.2",
4748
"lottie-react": "^2.4.1",
4849
"lucide-react": "^0.484.0",

src/components/render-props/ReactionStatus.tsx

Lines changed: 52 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
REACTION_TYPE,
66
ReactionStatus as ReactionStatusModel,
77
} from "@/backend/models/domain-models";
8+
import { useImmer } from "use-immer";
89

910
interface Props {
1011
resource_type: "ARTICLE" | "COMMENT";
@@ -26,6 +27,38 @@ const ReactionStatus: React.FC<Props> = ({
2627
render,
2728
}) => {
2829
const queryClient = useQueryClient();
30+
const [reactions, setReactions] = useImmer<ReactionStatusModel[]>([
31+
{
32+
count: 0,
33+
is_reacted: false,
34+
reaction_type: "CRY",
35+
},
36+
{
37+
count: 0,
38+
is_reacted: false,
39+
reaction_type: "FIRE",
40+
},
41+
{
42+
count: 0,
43+
is_reacted: false,
44+
reaction_type: "HAHA",
45+
},
46+
{
47+
count: 0,
48+
is_reacted: false,
49+
reaction_type: "LOVE",
50+
},
51+
{
52+
count: 0,
53+
is_reacted: false,
54+
reaction_type: "UNICORN",
55+
},
56+
{
57+
count: 0,
58+
is_reacted: false,
59+
reaction_type: "WOW",
60+
},
61+
]);
2962

3063
const query = useQuery({
3164
queryKey: ["reaction", resource_id, resource_type],
@@ -40,66 +73,42 @@ const ReactionStatus: React.FC<Props> = ({
4073
resource_type,
4174
reaction_type,
4275
}),
43-
onMutate: async (reaction_type: REACTION_TYPE) => {
44-
// Cancel any outgoing refetches
76+
async onMutate(reaction_type) {
77+
// cancel
4578
await queryClient.cancelQueries({
4679
queryKey: ["reaction", resource_id, resource_type],
4780
});
4881

49-
// Snapshot the previous value
50-
const previousReactions = queryClient.getQueryData<ReactionStatusModel[]>(
51-
["reaction", resource_id, resource_type]
52-
);
82+
const oldReactions = queryClient.getQueryData([
83+
"reaction",
84+
resource_id,
85+
resource_type,
86+
]);
5387

54-
// Optimistically update to the new value
55-
queryClient.setQueryData<ReactionStatusModel[]>(
88+
queryClient.setQueryData(
5689
["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-
}
90+
(old: ReactionStatusModel[]) => {
91+
const index = old.findIndex((r) => r.reaction_type == reaction_type);
92+
if (old[index].is_reacted) {
93+
old[index].is_reacted = false;
94+
--old[index].count;
7595
} 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-
];
96+
old[index].is_reacted = true;
97+
++old[index].count;
8798
}
99+
return old;
88100
}
89101
);
90102

91-
// Return a context object with the snapshotted value
92-
return { previousReactions };
103+
return { oldReactions };
93104
},
94-
onError: (err, reaction_type, context) => {
95-
// If the mutation fails, use the context returned from onMutate to roll back
105+
onError: (_, __, context) => {
96106
queryClient.setQueryData(
97107
["reaction", resource_id, resource_type],
98-
context?.previousReactions
108+
context?.oldReactions
99109
);
100110
},
101111
onSettled: () => {
102-
// Always refetch after error or success to ensure we have the latest data
103112
queryClient.invalidateQueries({
104113
queryKey: ["reaction", resource_id, resource_type],
105114
});

0 commit comments

Comments
 (0)