我正在 Next.js 中制作一个多选组件,并且正在使用状态和设置状态。但出现此错误:每当我单击此:
下面是MultiSelect.tsx的代码:
import { useState } from "react";
import {
Command,
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
CommandShortcut,
} from "@/components/ui/command";
interface MultiSelectProps {
placeholder: string
collections: CollectionType[]
value: string[]
onChange: (value: string) => void
onRemove: (value: string) => void
}
const MultiSelect: React.FC<MultiSelectProps> = ({
placeholder,
collections,
value,
onChange,
onRemove,
}) => {
const [inputValue, setInputValue] = useState("");
const [open, setOpen] = useState(false);
return (
<Command className="overflow-visible bg-white">
<CommandInput
placeholder={placeholder}
value={inputValue}
onValueChange={setInputValue}
onBlur={() => setOpen(false)}
onFocus={() => setOpen(true)}
/>
<div className="relative mt-2">
{open && (
<CommandGroup className="absolute w-full z-10 top-0 overflow-auto border rounded-md shadow-md">
{collections.map((collection) => (
<CommandItem key={collection._id}>{collection.title}</CommandItem>
))}
</CommandGroup>
)}
</div>
</Command>
);
};
export default MultiSelect;
另外,将 ProductForm.tsx 中的代码粘贴到此处:
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { Separator } from "../ui/separator";
import { z } from "zod";
import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Textarea } from "../ui/textarea";
import ImageUpload from "../custom ui/ImageUpload";
import { useParams, useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import toast from "react-hot-toast";
import Delete from "../custom ui/Delete";
import MultiText from "../custom ui/MultiText";
import MultiSelect from "../custom ui/MultiSelect";
const formSchema = z.object({
title: z.string().min(2).max(20),
description: z.string().min(2).max(500).trim(),
media: z.array(z.string()),
category: z.string(),
collections: z.array(z.string()),
tags: z.array(z.string()),
size: z.array(z.string()),
colors: z.array(z.string()),
price: z.coerce.number().min(0.1),
expense: z.coerce.number().min(0.1),
});
interface ProductFormProps {
initialData?: ProductType | null; // Must have ? to make it optional
}
const ProductForm: React.FC<ProductFormProps> = ({ initialData }) => {
const router = useRouter();
//const params = useParams();
const [loading, setLoading] = useState(false);
const [collections, setCollections] = useState<CollectionType[]>([]);
const getCollections = async () => {
try{
setLoading(true)
const res = await fetch("/api/collections", {
method: "GET",
})
const data = await res.json()
setCollections(data)
setLoading(false)
}catch(err) {
console.log("[collections_GET]", err)
toast.error("Something went wrong. Please try again.")
}
}
useEffect(() => {
getCollections()
}, [])
// 1. Define your form.
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: initialData
? initialData
: {
title: "",
description: "",
media: [],
category: "",
collections: [],
tags: [],
sizes: [],
colors: [],
price: 0.1,
expense: 0.1,
},
});
const handleKeyPress = (
e:
| React.KeyboardEvent<HTMLInputElement>
| React.KeyboardEvent<HTMLTextAreaElement>
) => {
if (e.key === "Enter") {
e.preventDefault();
}
};
// 2. Define a submit handler.
const onSubmit = async (values: z.infer<typeof formSchema>) => {
// Do something with the form values.
// ✅ This will be type-safe and validated.
//console.log(values)
try {
setLoading(true);
const url = initialData
? `/api/products/${initialData._id}`
: "/api/products";
const res = await fetch(url, {
method: "POST",
body: JSON.stringify(values),
});
if (res.ok) {
setLoading(false);
toast.success(`Product ${initialData ? "updated" : "created"}.`);
window.location.href = "/products";
router.push("/products");
}
} catch (err) {
console.log("[products_POST]", err);
toast.error("Something went wrong. Please try again.");
}
};
return (
<div className="p-10">
{initialData ? (
<div className="flex items-center justify-between">
<p className="text-heading2-bold">Edit Product</p>
<Delete id={initialData._id} />
</div>
) : (
<p className="text-heading2-bold">Create Product</p>
)}
<Separator className="bg-grey-1 my-4 mb-7" />
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="title"
render={({ field }) => (
<FormItem>
<FormLabel>Title</FormLabel>
<FormControl>
<Input
placeholder="Title"
{...field}
onKeyDown={handleKeyPress}
/>
</FormControl>
<FormDescription>The title of the product.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="description"
render={({ field }) => (
<FormItem>
<FormLabel>Description</FormLabel>
<FormControl>
<Textarea
placeholder="Description"
{...field}
rows={5}
onKeyDown={handleKeyPress}
/>
</FormControl>
<FormDescription>
The description of the product.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="media"
render={({ field }) => (
<FormItem>
<FormLabel>Image</FormLabel>
<FormControl>
<ImageUpload
value={field.value}
onChange={(url) => field.onChange([...field.value, url])}
onRemove={(url) =>
field.onChange([
...field.value.filter((image) => image !== url),
])
}
/>
</FormControl>
<FormDescription>The image of the product.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<div className="md: grid md:grid-cols-3 md:gap-8">
<FormField
control={form.control}
name="price"
render={({ field }) => (
<FormItem>
<FormLabel>Price ($)</FormLabel>
<FormControl>
<Input
type="number"
placeholder="Price"
{...field}
onKeyDown={handleKeyPress}
/>
</FormControl>
<FormDescription>The price of the product.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="expense"
render={({ field }) => (
<FormItem>
<FormLabel>Expense ($)</FormLabel>
<FormControl>
<Input
type="number"
placeholder="Expense"
{...field}
onKeyDown={handleKeyPress}
/>
</FormControl>
<FormDescription>The expense of the product.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="category"
render={({ field }) => (
<FormItem>
<FormLabel>Category</FormLabel>
<FormControl>
<Input
placeholder="Category"
{...field}
onKeyDown={handleKeyPress}
/>
</FormControl>
<FormMessage className="text-red-1" />
</FormItem>
)}
/>
<FormField
control={form.control}
name="tags"
render={({ field }) => (
<FormItem>
<FormLabel>Tags</FormLabel>
<FormControl>
<MultiText
placeholder="Tags"
value={field.value}
onChange={(tag) => field.onChange([...field.value, tag])}
onRemove={(tagToRemove) =>
field.onChange([
...field.value.filter((tag) => tag !== tagToRemove),
])
}
/>
</FormControl>
<FormMessage className="text-red-1" />
</FormItem>
)}
/>
<FormField
control={form.control}
name="collections"
render={({ field }) => (
<FormItem>
<FormLabel>Collections</FormLabel>
<FormControl>
<MultiSelect
placeholder="Collections"
collections={collections}
value={field.value}
onChange={(_id) => field.onChange([...field.value, _id])}
onRemove={(idToRemove) =>
field.onChange([
...field.value.filter((collectionId) => collectionId !== idToRemove),
])
}
/>
</FormControl>
<FormMessage className="text-red-1" />
</FormItem>
)}
/>
</div>
<div className="flex gap-10">
<Button type="submit" className="bg-blue-1 text-white">
Submit
</Button>
<Button
type="button"
onClick={() => router.push("/collections")}
className="bg-blue-1 text-white"
>
Discard
</Button>
</div>
</form>
</Form>
</div>
);
};
export default ProductForm;
单击多选组件时,它应该显示当前的集合列表。
我可以通过使用以下命令降级“cmdk”的版本来修复它:
npm install [email protected]