Next #06 Minibox 02

개미새·2024년 8월 14일

Next 가보자고

목록 보기
10/14

Supabase와 CRUD 개발을 했다면 기능을 구현해주자.

  1. Seach는 간단하게 Onchange 이벤트가 발생하면 찾을 수 있도록 개발.

components/searchComponent.tsx

"use client";

import { Input } from "@material-tailwind/react";

export default function SearchComponent({ searchInput, setSearchInput }){
    return (
        <Input
        value={searchInput}
        onChange={(e) => setSearchInput(e.target.value)}
        label="Search Image"
        icon={<i className="fa-solid fa-magnifying-glass" />}
        />
    )
}
  1. File Drag Drop
    React-Query의 useMutation 와 react-dropzone 라이브러리를 활용해 개발을 진행했다.

components/file-dragdropzone.tsx

"use client";

import { Spinner } from "@material-tailwind/react";
import { useMutation } from "@tanstack/react-query";
import { uploadFile } from "actions/storageActions";
import { queryClient } from "config/ReactClientProivider";
import { useCallback } from "react";
import { useDropzone } from "react-dropzone";

export default function FileDragDropZone(){
    const uploadImageMutation = useMutation({
        mutationFn: uploadFile,
        onSuccess: () => {
            queryClient.invalidateQueries({
                queryKey: ["images"],
            })
        }
    });

    const onDrop = useCallback( async (acceptedFiles) => {
        if(acceptedFiles.length > 0){
            const formData = new FormData();

            acceptedFiles.forEach((file) => {
                formData.append(file.name, file);
            });
            const result = await uploadImageMutation.mutate(formData);
        }
    }, []);
    const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });

    return (
        <div
            {...getRootProps()}
            className="w-full py-20 border-4 border-dotted border-indigo-700 flex flex-col items-center justify-center cursor-pointer">
            <input {...getInputProps()} />
            {uploadImageMutation.isPending ? (<Spinner />) :
            ( isDragActive ? (
                    <p>파일을 놓아주세요.</p>
                ) : (
                    <p>파일을 여기에 끌어다 놓거나 클릭하여 업로드하세요.</p>
                )
            )}
        </div>
    )
}
  1. ImageList

components/dropbox-image-list.tsx

"use client";

import { useQuery } from "@tanstack/react-query";
import DropboxImage from "./dropbox-image";
import { searchFiles } from "actions/storageActions";
import { Spinner } from "@material-tailwind/react";

export default function DropboxImageList({ searchInput }) {
    const searchImageQuery = useQuery({
        queryKey: ["images", searchInput],
        queryFn: () => searchFiles(searchInput),
    })

    return (
        <section className="grid md:grid-cols-3 lg:grid-cols-4 grid-cols-2">
            {searchImageQuery.isLoading && <Spinner />}
            {searchImageQuery.data &&
            searchImageQuery.data.map(image =>(
            <DropboxImage key={image.id} image={image} />
            ))}
        </section>
    )
}
  1. Image
import { IconButton, Spinner } from "@material-tailwind/react";
import { useMutation } from "@tanstack/react-query";
import { deleteFile } from "actions/storageActions";
import { queryClient } from "config/ReactClientProivider";
import { getImageUrl } from "utils/supabase/storage";

export default function DropboxImage({ image }){
    const deleteFileMutation = useMutation({
        mutationFn: deleteFile,
        onSuccess: () => {
            queryClient.invalidateQueries({
                queryKey: ["images"],
            })
        }
    })

    return (
        <div className="relative w-full flex flex-col gap-2 p-4 border borer-gray-100 rounded-2xl shadow-md">
            {/* Image */}
            <div>
                <img src={getImageUrl(image.name)} className="w-full aspect-square rounded-2xl" />
            </div>

            {/* File Name */}
            <div className="font-bold">{image.name}</div>

            {/* Delete Button */}
            <div className="absolute top-2 right-4">
                <IconButton color="red" onClick={() => {deleteFileMutation.mutate(image.name);}}>
                    {deleteFileMutation.isPending ? ( <Spinner /> ) : (
                        <i className="fas fa-trash" />
                    )}
                </IconButton>
            </div>
        </div>
    )
}

이렇게 해서 간단하게 File Upload 할 수 있는 Minibox를 만들어 보았다.

간단하지만 CRUD 나 React-Query에 활용까지 공부할 수 있었고,
File을 FormData에 저장해서 한번에 한개씩 올리는 것과 여러개를 올리는 방식에 대해서도 배울 수 있었다.
간단한 기초지만 이것부터 하나하나 배우면서 활용할 수 있도록 내꺼로 만들어야겠다.

완성

GitHub : https://github.com/saemiprk/next-dropbox

profile
개미는 뚠뚠🐜🐜 개발에 미친 새미의 개발 이야기

0개의 댓글