From 987f78ac25af119796c6f3830a61aafcabeb2dc1 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Fri, 22 Aug 2025 23:17:09 +0900 Subject: fix(frontend): wrong optimistic update --- frontend/src/components/ArticleItem.tsx | 38 +++++++++++---------------------- frontend/src/components/ArticleList.tsx | 28 ++++++++++++++++++++---- frontend/src/pages/ReadArticles.tsx | 4 +++- frontend/src/pages/UnreadArticles.tsx | 4 +++- 4 files changed, 43 insertions(+), 31 deletions(-) (limited to 'frontend/src') diff --git a/frontend/src/components/ArticleItem.tsx b/frontend/src/components/ArticleItem.tsx index faa86fe..4942518 100644 --- a/frontend/src/components/ArticleItem.tsx +++ b/frontend/src/components/ArticleItem.tsx @@ -1,6 +1,5 @@ import { faCheck, faCircle } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { useOptimistic } from "react"; import { useMutation } from "urql"; import type { GetReadArticlesQuery, @@ -18,27 +17,19 @@ type Article = NonNullable< interface Props { article: Article; + onReadChange?: (articleId: string, isRead: boolean) => void; } -export function ArticleItem({ article }: Props) { +export function ArticleItem({ article, onReadChange }: Props) { const [, markArticleRead] = useMutation(MarkArticleReadDocument); const [, markArticleUnread] = useMutation(MarkArticleUnreadDocument); - const [optimisticArticle, setOptimisticArticle] = useOptimistic( - article, - (currentArticle, newReadState: boolean) => ({ - ...currentArticle, - isRead: newReadState, - }), - ); - const handleToggleRead = async ( articleId: string, isCurrentlyRead: boolean, ) => { const newReadState = !isCurrentlyRead; - - setOptimisticArticle(newReadState); + onReadChange?.(articleId, newReadState); if (isCurrentlyRead) { await markArticleUnread({ id: articleId }); @@ -50,9 +41,8 @@ export function ArticleItem({ article }: Props) { const handleArticleClick = async (article: Article) => { // Open article in new tab and mark as read if it's unread window.open(article.url, "_blank", "noreferrer"); - if (!optimisticArticle.isRead) { - setOptimisticArticle(true); - + if (!article.isRead) { + onReadChange?.(article.id, true); await markArticleRead({ id: article.id }); } }; @@ -60,38 +50,36 @@ export function ArticleItem({ article }: Props) { return (
diff --git a/frontend/src/components/ArticleList.tsx b/frontend/src/components/ArticleList.tsx index 2ea94f0..574f529 100644 --- a/frontend/src/components/ArticleList.tsx +++ b/frontend/src/components/ArticleList.tsx @@ -1,3 +1,4 @@ +import { useState } from "react"; import type { GetReadArticlesQuery, GetUnreadArticlesQuery, @@ -9,17 +10,32 @@ interface Props { | GetUnreadArticlesQuery["unreadArticles"] | GetReadArticlesQuery["readArticles"] >; + isReadView?: boolean; } -export function ArticleList({ articles }: Props) { - if (articles.length === 0) { +export function ArticleList({ articles, isReadView }: Props) { + const [hiddenArticleIds, setHiddenArticleIds] = useState>( + new Set(), + ); + + const handleArticleReadChange = (articleId: string, isRead: boolean) => { + if (isReadView !== isRead) { + setHiddenArticleIds((prev) => new Set(prev).add(articleId)); + } + }; + + const visibleArticles = articles.filter( + (article) => !hiddenArticleIds.has(article.id), + ); + + if (visibleArticles.length === 0) { return (
No articles found.
); } // Group articles by feed - const articlesByFeed = articles.reduce( + const articlesByFeed = visibleArticles.reduce( (acc, article) => { const feedId = article.feed.id; if (!acc[feedId]) { @@ -50,7 +66,11 @@ export function ArticleList({ articles }: Props) {
{feedArticles.map((article) => ( - + ))}
diff --git a/frontend/src/pages/ReadArticles.tsx b/frontend/src/pages/ReadArticles.tsx index 44ae834..74c1f5c 100644 --- a/frontend/src/pages/ReadArticles.tsx +++ b/frontend/src/pages/ReadArticles.tsx @@ -26,7 +26,9 @@ export function ReadArticles() {

)} - {data?.readArticles && } + {data?.readArticles && ( + + )} ); } diff --git a/frontend/src/pages/UnreadArticles.tsx b/frontend/src/pages/UnreadArticles.tsx index f82d4dc..45ae0f9 100644 --- a/frontend/src/pages/UnreadArticles.tsx +++ b/frontend/src/pages/UnreadArticles.tsx @@ -26,7 +26,9 @@ export function UnreadArticles() {

)} - {data?.unreadArticles && } + {data?.unreadArticles && ( + + )} ); } -- cgit v1.2.3-70-g09d2