Unverified 提交 a4747a49 authored 作者: Will Chen's avatar Will Chen 提交者: GitHub

Use idiomatic react-query for useProposal (#2018)

<!-- CURSOR_SUMMARY --> > [!NOTE] > **Refactor: proposal fetching via react-query** > > - Replaces Jotai state/effects with `useQuery` in `useProposal` (`queryKey: ["proposal", chatId]`, `enabled` gating, `refetch` exposed, error typed as `Error`) > - Deletes `src/atoms/proposalAtoms.ts`; `proposalResultAtom` removed > - In `useStreamChat`, stop using `useProposal`; on stream end, call `queryClient.invalidateQueries({ queryKey: ["proposal", chatId] })` > - In `ChatInput`, display `proposalError.message` and keep using `refreshProposal()` from the hook > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 9739b1befe76a7cb491594815d3d92977ad6a1c6. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Refactored proposal fetching to use React Query’s useQuery, removing Jotai state and simplifying refresh and error handling. Improves reliability and makes the hook easier to use. - **Refactors** - Replaced custom state/effects with useQuery (key: ["proposal", chatId], enabled only when chatId). - Removed proposalAtoms and Jotai; hook now returns proposalResult, isLoading, error, refreshProposal. - Updated useStreamChat to invalidate the proposal query via QueryClient (invalidateQueries(["proposal", chatId])). - ChatInput now displays proposalError.message for clearer errors. - Added meta: { showErrorToast: true } to surface fetch errors. <sup>Written for commit 9739b1befe76a7cb491594815d3d92977ad6a1c6. Summary will update automatically on new commits.</sup> <!-- End of auto-generated description by cubic. -->
上级 04087298
import { atom } from "jotai";
import type { ProposalResult } from "@/lib/schemas";
export const proposalResultAtom = atom<ProposalResult | null>(null);
......@@ -305,7 +305,7 @@ export function ChatInput({ chatId }: { chatId?: number }) {
)}
{proposalError && (
<div className="p-4 text-sm text-red-600">
Error loading proposal: {proposalError}
Error loading proposal: {proposalError.message}
</div>
)}
<div className="p-4" data-testid="chat-input-container">
......
import { useState, useEffect, useCallback } from "react";
import { useQuery } from "@tanstack/react-query";
import { IpcClient } from "@/ipc/ipc_client";
import type { ProposalResult } from "@/lib/schemas"; // Import Proposal type
import { proposalResultAtom } from "@/atoms/proposalAtoms";
import { useAtom } from "jotai";
import type { ProposalResult } from "@/lib/schemas";
export function useProposal(chatId?: number | undefined) {
const [proposalResult, setProposalResult] = useAtom(proposalResultAtom);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);
const fetchProposal = useCallback(
async (overrideChatId?: number) => {
chatId = overrideChatId ?? chatId;
const {
data: proposalResult,
isLoading,
error,
refetch: refreshProposal,
} = useQuery<ProposalResult | null, Error>({
queryKey: ["proposal", chatId],
queryFn: async (): Promise<ProposalResult | null> => {
if (chatId === undefined) {
setProposalResult(null);
setIsLoading(false);
setError(null);
return;
}
setIsLoading(true);
setError(null);
try {
// Type assertion might be needed depending on how IpcClient is typed
const result = (await IpcClient.getInstance().getProposal(
chatId,
)) as ProposalResult | null;
if (result) {
setProposalResult(result);
} else {
setProposalResult(null); // Explicitly set to null if IPC returns null
}
} catch (err: any) {
console.error("Error fetching proposal:", err);
setError(err.message || "Failed to fetch proposal");
setProposalResult(null); // Clear proposal data on error
} finally {
setIsLoading(false);
return null;
}
return IpcClient.getInstance().getProposal(chatId);
},
[chatId], // Only depend on chatId, setProposalResult is stable
); // Depend on chatId
useEffect(() => {
fetchProposal();
// Cleanup function if needed (e.g., for aborting requests)
// return () => {
// // Abort logic here
// };
}, [fetchProposal]); // Re-run effect if fetchProposal changes (due to chatId change)
enabled: chatId !== undefined,
meta: { showErrorToast: true },
});
return {
proposalResult: proposalResult,
proposalResult,
isLoading,
error,
refreshProposal: fetchProposal, // Expose the refresh function
refreshProposal,
};
}
......@@ -20,7 +20,6 @@ import { useLoadApp } from "./useLoadApp";
import { selectedAppIdAtom } from "@/atoms/appAtoms";
import { useVersions } from "./useVersions";
import { showExtraFilesToast } from "@/lib/toast";
import { useProposal } from "./useProposal";
import { useSearch } from "@tanstack/react-router";
import { useRunApp } from "./useRunApp";
import { useCountTokens } from "./useCountTokens";
......@@ -28,6 +27,7 @@ import { useUserBudgetInfo } from "./useUserBudgetInfo";
import { usePostHog } from "posthog-js/react";
import { useCheckProblems } from "./useCheckProblems";
import { useSettings } from "./useSettings";
import { useQueryClient } from "@tanstack/react-query";
export function getRandomNumberId() {
return Math.floor(Math.random() * 1_000_000_000_000_000);
......@@ -54,13 +54,13 @@ export function useStreamChat({
const { settings } = useSettings();
const setRecentStreamChatIds = useSetAtom(recentStreamChatIdsAtom);
const posthog = usePostHog();
const queryClient = useQueryClient();
let chatId: number | undefined;
if (hasChatId) {
const { id } = useSearch({ from: "/chat" });
chatId = id;
}
let { refreshProposal } = hasChatId ? useProposal(chatId) : useProposal();
const { invalidateTokenCount } = useCountTokens(chatId ?? null, "");
const streamMessage = useCallback(
......@@ -141,7 +141,8 @@ export function useStreamChat({
posthog,
});
}
refreshProposal(chatId);
// Use queryClient directly with the chatId parameter to avoid stale closure issues
queryClient.invalidateQueries({ queryKey: ["proposal", chatId] });
refetchUserBudget();
......@@ -205,6 +206,7 @@ export function useStreamChat({
selectedAppId,
refetchUserBudget,
settings,
queryClient,
],
);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论