Product - Router

์ด๋™์–ธยท2024๋…„ 9์›” 25์ผ

new world

๋ชฉ๋ก ๋ณด๊ธฐ
49/62
post-thumbnail

9.25 (์ˆ˜)

1. useCallBack

๐Ÿ‘‰ useCallback์€ ํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•˜์—ฌ, ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ํ•œ ์ด์ „์— ์ƒ์„ฑ๋œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉ. inputํƒœ๊ทธ์—์„œ ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•œ๊ฒƒ์€ ํ•œ ๊ธ€์ž์”ฉ ์ž‘์„ฑํ•  ๋•Œ๋งˆ๋‹ค handleChange๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์–ด ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š”๋ฐ, usecallback์„ ์ด์šฉํ•˜๋ฉด handleChange๊ฐ€ ๊ฐ™์€ ์ฐธ์กฐ๋ฅผ ๊ฐ€์ง€๋Š” ๋ฉ”๋ชจ์ด์ œ์ด์…˜์—ญํ• ์„ ํ•œ๋‹ค.

function TodoAddComponent() {

 const handleChange = useCallback((e:ChangeEvent<HTMLInputElement>) => {

        // @ts-ignore
        todo[e.target.name] = e.target.value
        setTodo({...todo})
   	 },[])
    
 return (
 <input
                type="text"
                name="title"
                className="border border-gray-300 rounded-lg p-3 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition duration-300"
                placeholder="Enter Title"
                value={todo.title}
                onChange={e => handleChange(e)}
            />
            )
 
    }
  




2. formData

2-1. ProductAddPage.tsx

import {ChangeEvent, useRef, useState} from "react";
import {postAdd} from "../../api/productAPI.ts";

const initialState = {
    pname: '',
    pdesc: '',
    price: '',
}


function ProductAddPage() {

    const [product, setProduct] = useState({...initialState}) // ์ดˆ๊ธฐ๊ฐ’์ด ์—†์œผ๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ• ์ˆ˜์žˆ์œผ๋ฏ€๋กœ ๋ณต์‚ฌ๋ณธ ๋„ฃ๊ธฐ
    const filesRef = useRef<HTMLInputElement>(null) // id,name์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹ ์—

    const handleChange = (e:ChangeEvent<HTMLInputElement>) => {
        product[e.target.name] = e.target.value
    }

    const handleClick = () => {

        const files = filesRef.current.files // ๋“ฑ๋กํ•œ ํŒŒ์ผ์— ๋Œ€ํ•œ ์ •๋ณด

        console.log(filesRef)

        const formData = new FormData() // ํŒŒ์ผ ์—…๋กœ๋“œ์™€ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•˜๊ธฐ์œ„ํ•ด ์ผ๋ฐ˜์ ์ธ json๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

        formData.append("pname", product.pname)
        formData.append("pdesc", product.pdesc)
        formData.append("price", product.price)

        for(let i=0; i<files.length; i++) {
            formData.append("files", files[i])
        }

        postAdd(formData).then(data =>{
            console.log(data)
            filesRef.current.value = null
        })


    }


    return (
        <div>
            <div>Product Add Page</div>

            <div>

                <input type='text' name='pname' placeholder='Product Name' onChange={(e) => handleChange(e)}/>
                <input type='text' name='pdesc' placeholder='Product Desc' onChange={(e) => handleChange(e)}/>
                <input type='number' name='price' placeholder='1000' onChange={(e) => handleChange(e)}/>
                <input type='file' ref={filesRef} name='files' multiple={true}/>

                <button onClick={() => handleClick()}>ADD</button>

            </div>

        </div>
    );
}

export default ProductAddPage;

๐Ÿ‘‰ ๊ธฐ๋ณธ์ ์œผ๋กœ input ํƒœ๊ทธ๋ฅผ ์ด์šฉํ•œ addํŽ˜์ด์ง€์—์„œ๋Š” useState๋ฅผ ์ด์šฉํ•œ ์ƒํƒœ๊ฐ์ฒด์— handleChange ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ product[e.target.name] = e.target.value ์ด๊ฒƒ์ฒ˜๋Ÿผ ๋„ฃ์–ด์„œ api์„œ๋ฒ„์— prodcut๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ, ์ฒจ๋ถ€ํŒŒ์ผ์ด ๋“ค์–ด๊ฐ€๋Š” ๊ฒฝ์šฐ๋Š” ๋‹ค๋ฅด๋‹ค

๐Ÿ‘‰ ์šฐ์„  useRef๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด filesRef.current.files ํ•ด๋‹น ์†์„ฑ์„ ์ด์šฉํ•˜์—ฌ ๋“ฑ๋กํ•œ ํŒŒ์ผ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ์ด ์ •๋ณด๋Š” inputํƒœ๊ทธ๋‚ด์— file type์— ref={filesRef}๋ฅผ ์ด์šฉํ•˜์—ฌ inputํƒœ๊ทธ์˜ file์†์„ฑ์„ ๋œปํ•œ๋‹ค. ๋ช‡๊ฐœ์˜ ํŒŒ์ผ์„ ์ฒจ๋ถ€ํ–ˆ๋Š”์ง€์™€ ๊ฐ™์€ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ์ˆ˜๋„ ์žˆ๋‹ค.

๐Ÿ‘‰ ์ดํ›„์—๋Š” formData ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์•ผํ•˜๋Š”๋ฐ, ์ด๋Š” ํŒŒ์ผ์—…๋กœ๋“œ์™€ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด ์ผ๋ฐ˜์ ์ธ json ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋Š” formData๊ฐ์ฒด์— append๋กœ ๊ฐ๊ฐ ๋ถ™ํ˜€์ฃผ๊ณ  file๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š” filesRef์˜ file๊ฐœ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ช‡๊ฐœ์ธ์ง€ ํŒŒ์•…ํ•˜์—ฌ file์„ appendํ•ด์ค€๋‹ค.

๐Ÿ‘‰ ๋งˆ์ง€๋ง‰์œผ๋กœ api์„œ๋ฒ„ ํ˜ธ์ถœํ•˜์—ฌ post๋ฅผ ํ•ด์ค€๋’ค์— filesRef.current.value = null ์ด ์ฝ”๋“œ๋Š” ์ด์ „์— ์ž…๋ ฅํ•œ file์„ ์ง€์›Œ์„œ ๋‹ค์Œ post์‹œ์— ํŽธํ•˜๋„๋ก ๋น„์›Œ์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.



2-2. ProductAPI.ts

import axios from "axios";


const host:string = 'http://localhost:8089/api/products'

const header = { //post๋ฐฉ์‹์—์„œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋˜์ง€๋งŒ, put์—์„œ๋Š” ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.
    headers: {
        'Content-Type': 'multipart/form-data', // ํŒŒ์ผ ์ „์†ก ํ˜•์‹ ์ง€์ •
    }
}

export const postAdd = async (formData: FormData): Promise<number> => {

    const res = await axios.post(`${host}/`, formData)
    return Number(res.data.result) // ๋“ฑ๋ก์‹œ์— result์™€ ์ˆœ๋ฒˆ๊ฐ’์ด ๋‚˜์˜ค๋ฏ€๋กœ data.result์ด๊ณ  ํƒ€์ž…์€ number

}

๐Ÿ‘‰ API ๋˜ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜์— ํŒŒ์ผ์ด ํฌํ•จ๋˜์–ด์žˆ์œผ๋ฏ€๋กœ ํƒ€์ž…์„ formData๋กœ ์„ค์ •ํ•œ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€