📑
【NextJs14】NextJs14 と 便利なライブラリ【#26 Upload Images Preview】
【#26 Upload Images Preview】
YouTube: https://youtu.be/hCbDmfsV8HU
今回は選択した画像のプレビューの表示と
選択を解除するボタンを実装します。
app/(main)/images/_components/images-form.tsx
"use client";
import { useState } from "react";
import * as z from "zod";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { UploadImagesForm } from "@/components/forms/upload-images-form";
import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
} from "@/components/ui/form";
const formSchema = z.object({
images: z.object({ url: z.string() }).array(),
});
export const ImagesForm = () => {
const [isLoading, setIsLoading] = useState(false);
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
images: [],
},
});
const onSubmit = (values: z.infer<typeof formSchema>) => {
setIsLoading(true);
alert(JSON.stringify(values.images, null, 2));
setIsLoading(false);
};
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="flex flex-col space-y-4"
>
<FormField
control={form.control}
name="images"
render={({ field }) => (
<FormItem>
<FormLabel>Images upload button</FormLabel>
<FormControl>
<UploadImagesForm
value={field.value.map((image) => image.url)}
onChange={(url: string) =>
field.onChange([...field.value, { url }])
}
onRemove={(url: string) =>
field.onChange([
...field.value.filter((current) => current.url !== url),
])
}
disabled={isLoading}
/>
</FormControl>
</FormItem>
)}
/>
<Button type="submit" variant="primary" disabled={isLoading}>
Submit
</Button>
</form>
</Form>
);
};
conponents/forms/upload-images-form.tsx
"use client";
import Image from "next/image";
import { CldUploadWidget } from "next-cloudinary";
import { ImagePlus, Trash } from "lucide-react";
import { useIsClient } from "usehooks-ts";
import { Button } from "@/components/ui/button";
interface UploadImagesFormProps {
onChange: (url: string) => void;
onRemove: (url: string) => void;
value: string[];
disabled?: boolean;
}
export const UploadImagesForm = ({
onChange,
onRemove,
value,
disabled,
}: UploadImagesFormProps) => {
const isClient = useIsClient();
const onUpload = (result: any) => {
onChange(result.info.secure_url);
};
if (!isClient) {
return null;
}
return (
<div>
<div className="flex items-center gap-3 mb-3">
{value.map((url) => (
<div className="relative w-[16em] h-[9em] rounded-md overflow-hidden">
<div className="z-50 absolute top-3 right-3">
<Button
type="button"
disabled={disabled}
onClick={() => onRemove(url)}
>
<Trash className="h-4 w-4" />
</Button>
</div>
<Image src={url} alt="image" fill className="object-cover" />
</div>
))}
</div>
<CldUploadWidget onUpload={onUpload} uploadPreset="iv6ye3lb">
{({ open }) => {
const onClick = () => {
open();
};
return (
<Button type="button" variant="default" onClick={onClick}>
<ImagePlus className="w-4 h-4 mr-2" />
Upload your images
</Button>
);
}}
</CldUploadWidget>
</div>
);
};
Discussion