我正在尝试将我的库 tanstack/query v4 更新为 v5 (https://tanstack.com/query/v5/docs/react/guides/migration-to-v5),但我已阅读文档我在迁移版本时遇到问题,尤其是使用命令
命令:
$ npx jscodeshift@latest ./path/to/src/ \
--extensions=ts,tsx \
--parser=tsx \
--transform=./node_modules/@tanstack/react-query/build/codemods/src/v5/remove-overloads/remove-overloads.js
我需要有人更新所有 4 个文件的语法,而不需要这个命令。
事件.组件.tsx
import React, { FC, useEffect, useState } from "react";
import { format, parseISO } from "date-fns";
import { twMerge } from "tailwind-merge";
import EventModal from "../event.modal";
import UpdateEvent from "./update.event";
import { toast } from "react-toastify";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import NProgress from "nprogress";
import { IEvent } from "../../api/types";
import { deleteEventFn } from "../../api/eventApi";
type EventItemProps = {
event: IEvent;
};
const EventItem: FC<EventItemProps> = ({ event }) => {
const [openSettings, setOpenSettings] = useState(false);
const [openEventModal, setOpenEventModal] = useState(false);
// My addition
useEffect(() => {
const handleOutsideClick = (event: MouseEvent) => {
const target = event.target as HTMLElement;
const dropdown = document.getElementById(`settings-dropdown-${event.id}`);
if (dropdown && !dropdown.contains(target)) {
setOpenSettings(false);
}
};
document.addEventListener("mousedown", handleOutsideClick);
return () => {
document.removeEventListener("mousedown", handleOutsideClick);
};
}, [event.id]);
const queryClient = useQueryClient();
const { mutate: deleteEvent } = useMutation({
mutationFn: (eventId: string) => deleteEventFn(eventId),
onMutate() {
NProgress.start();
},
onSuccess(data) {
queryClient.invalidateQueries({
queryKey: ["getEvents"]
});
toast("Event deleted successfully", {
type: "warning",
position: "top-right",
});
NProgress.done();
},
onError(error: any) {
const resMessage =
error.response.data.message ||
error.response.data.detail ||
error.message ||
error.toString();
toast(resMessage, {
type: "error",
position: "top-right",
});
NProgress.done();
},
});
const onDeleteHandler = (eventId: string) => {
if (window.confirm("Are you sure")) {
deleteEvent(eventId);
}
};
return (
<>
...
</>
);
};
export default EventItem;
更新.event.tsx
import { FC, useEffect } from "react";
import { SubmitHandler, useForm } from "react-hook-form";
import { twMerge } from "tailwind-merge";
import { object, string, TypeOf } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { LoadingButton } from "../LoadingButton";
import { toast } from "react-toastify";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { IEvent } from "../../api/types";
import { updateEventFn } from "../../api/eventApi";
type IUpdateEventProps = {
event: IEvent;
setOpenEventModal: (open: boolean) => void;
};
const updateEventSchema = object({
title: string().min(1, "Title is required"),
content: string().min(1, "Content is required"),
});
export type UpdateEventInput = TypeOf<typeof updateEventSchema>;
const UpdateEvent: FC<IUpdateEventProps> = ({ event, setOpenEventModal }) => {
const methods = useForm<UpdateEventInput>({
resolver: zodResolver(updateEventSchema),
});
const {
register,
handleSubmit,
formState: { errors },
} = methods;
useEffect(() => {
if (event) {
methods.reset(event);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const queryClient = useQueryClient();
const { mutate: updateEvent } = useMutation({
mutationFn: ({ eventId, event }: { eventId: string; event: UpdateEventInput }) =>
updateEventFn(eventId, event),
onSuccess(data) {
queryClient.invalidateQueries({
queryKey: ["getEvents"]
});
setOpenEventModal(false);
toast("Event updated successfully", {
type: "success",
position: "top-right",
});
},
onError(error: any) {
setOpenEventModal(false);
const resMessage =
error.response.data.message ||
error.response.data.detail ||
error.message ||
error.toString();
toast(resMessage, {
type: "error",
position: "top-right",
});
},
});
const onSubmitHandler: SubmitHandler<UpdateEventInput> = async (data) => {
updateEvent({ eventId: event.id, event: data });
};
return (
<section>
...
</section>
);
};
export default UpdateEvent;
创建.event.tsx
import { FC } from "react";
import { SubmitHandler, useForm } from "react-hook-form";
import { twMerge } from "tailwind-merge";
import { object, string, TypeOf } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { LoadingButton } from "../LoadingButton";
import { toast } from "react-toastify";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { createEventFn } from "../../api/eventApi";
import NProgress from "nprogress";
type ICreateEventProps = {
setOpenEventModal: (open: boolean) => void;
};
const createEventSchema = object({
title: string().min(1, "Title is required"),
content: string().min(1, "Content is required"),
});
export type CreateEventInput = TypeOf<typeof createEventSchema>;
const CreateEvent: FC<ICreateEventProps> = ({ setOpenEventModal }) => {
const methods = useForm<CreateEventInput>({
resolver: zodResolver(createEventSchema),
});
const {
register,
handleSubmit,
formState: { errors },
} = methods;
const queryClient = useQueryClient();
const { mutate: createEvent } = useMutation({
mutationFn: (event: CreateEventInput) => createEventFn(event),
onMutate() {
NProgress.start();
},
onSuccess(data) {
queryClient.invalidateQueries({
queryKey: ["getEvents"]
});
setOpenEventModal(false);
NProgress.done();
toast("Event created successfully", {
type: "success",
position: "top-right",
});
},
onError(error: any) {
setOpenEventModal(false);
NProgress.done();
const resMessage =
error.response.data.message ||
error.response.data.detail ||
error.message ||
error.toString();
toast(resMessage, {
type: "error",
position: "top-right",
});
},
});
const onSubmitHandler: SubmitHandler<CreateEventInput> = async (data) => {
createEvent(data);
};
return (
<section>
...
</section>
);
};
export default CreateEvent;
应用程序.tsx
import "react-toastify/dist/ReactToastify.css";
import {
QueryClient,
QueryClientProvider,
useQuery,
} from "@tanstack/react-query";
import { useEffect, useState } from "react";
import { toast, ToastContainer } from "react-toastify";
import { getEventsFn } from "./api/eventApi";
import EventModal from "./components/event.modal";
import CreateEvent from "./components/events/create.event";
import EventItem from "./components/events/event.component";
import NProgress from "nprogress";
function AppContent() {
const [openEventModal, setOpenEventModal] = useState(false);
const {
data: events,
isLoading,
isFetching,
} = useQuery({
queryKey: ["getEvents"],
queryFn: () => getEventsFn(),
staleTime: 5 * 1000,
select: (data) => data.events,
onSuccess() {
NProgress.done();
},
onError(error: any) {
const resMessage =
error.response.data.message ||
error.response.data.detail ||
error.message ||
error.toString();
toast(resMessage, {
type: "error",
position: "top-right",
});
NProgress.done();
},
});
useEffect(() => {
if (isLoading || isFetching) {
NProgress.start();
}
}, [isLoading, isFetching]);
return (
<div className="2xl:max-w-[90rem] max-w-[68rem] mx-auto">
<div className="m-8 grid grid-cols-[repeat(auto-fill,_320px)] gap-7 grid-rows-[1fr]">
<div className="p-4 min-h-[18rem] bg-white rounded-lg border border-gray-200 shadow-md flex flex-col items-center justify-center">
<div
onClick={() => setOpenEventModal(true)}
className="flex items-center justify-center h-20 w-20 border-2 border-dashed border-ct-blue-600 rounded-full text-ct-blue-600 text-5xl cursor-pointer"
>
<i className="bx bx-plus"></i>
</div>
<h4
onClick={() => setOpenEventModal(true)}
className="text-lg font-medium text-ct-blue-600 mt-5 cursor-pointer"
>
Add new event
</h4>
</div>
{/* Event Items */}
{events?.map((event) => (
<EventItem key={event.id} event={event} />
))}
{/* Create Event Modal */}
<EventModal
openEventModal={openEventModal}
setOpenEventModal={setOpenEventModal}
>
<CreateEvent setOpenEventModal={setOpenEventModal} />
</EventModal>
</div>
</div>
);
}
function App() {
const [queryClient] = useState(() => new QueryClient());
return (
<>
<QueryClientProvider client={queryClient}>
</QueryClientProvider>
</>
);
}
export default App;
您在使用此命令时遇到了什么问题?