프론트엔드/React&JS

이미지를 서버에 전송해보자. (feat. FormData, async/await)

정예지 2022. 9. 2. 20:23

상품을 등록할 때 이미지도 서버에 전송해야하는데, 어떻게 해도 제대로 보내지지 않아서 엄청난 삽질을 했다.

1. 내가 한 어이없는 실수

// 미리보기 이미지
    const handleImageInput = (e) => {
        setPreview(URL.createObjectURL(e.target.files[0]));
    };

이건 이미지 미리보기를 구현한건데 이 값을 그대로 보내려고 했다…

 blob:http://주소/cb21c13b-1944-42ad-8aa4-94611177989a

이렇게 나와서 또 다른 실수를 하고야 마는데 …

앞에 blob:을 자르고 보내려고 한다 🤦‍♀️ (당연히 보내질리가…)

뭔가 FormData 를 사용해야하는 것은 알겠는데 … 명확하게 어떻게 사용해야할지 몰라서 굉장히 많은 방황을 했다.

2. 해결 방법

우선 API를 살펴보니 이미지를 따로 업로드하는 API가 있었다!

우선 폼제출 전에 이미지 데이터를 받아와서 폼제출을 완료하면 될 것 같다는 생각이 들었다.

// 이미지 업로드
const uploadImage = async () => {
        let formData = new FormData(); // FormData 생성
        const imgFile = inpRef.current.files; // 이미지 파일 가져오기
        const file = imgFile[0]; // 이미지 파일이 한개라 0번 인덱스에 접근해 값 가져오기
        formData.append('image', file); // image라는 키에 file이라는 값 넣기
        const res = await axios.post( // await에 넘겨서 완료 될 때까지 기다리기
            '<https://주소/image/uploadfile>',
            formData
        );
        const imgUrl = `https://주소/${res.data.filename}`;
				// 보낸 이미지 파일 데이터 받아서 저장
        return imgUrl;
    };
  1. 폼 제출 전에 실행해야하니 async function으로 비동기 함수를 정의해준다.
  2. file을 key/value 로 보낼 것이기 때문에 new FormData()FormData를 생성해준다.
  3. 이미지 파일에 접근해 값 가져오기
  4. FormData에 key, value 넣어주기
  5. await으로 이미지 파일이름 받아오기
// 상품등록 데이터 전송
    const createProduct = async (e) => {
        e.preventDefault();
        if (state) {
            // 추후에 로그인 기능 구현되면 삭제. 일회성 토큰
            const url = '<https://주소.co.kr>';
            const getToken = localStorage.getItem('token');
            const res = uploadImage();
            try {
                await axios.post(
                    `${url}/product`,
                    {
                        product: {
                            itemName: name,
                            price: parseInt(
                                price
                                    .split(',')
                                    .reduce((curr, acc) => curr + acc, '')
                            ),
                            link: link,
                            itemImage: await res, // 이미지 파일 데이터 받아오기
                        },
                    },
                    {
                        headers: {
                            'Authorization': `Bearer ${getToken}`,
                            'Content-type': 'application/json',
                        },
                    }
                );
                navigate('/myprofile');
            } catch (error) {
                console.log(error);
            }
        }
    };
  1. 폼을 제출하는 함수에서 비동기로 먼저 const res = uploadImage(); 를 실행해 이미지 파일 데이터를 받아온다.
  2. itemImage에 이미지 파일 데이터를 받아오고 난 뒤 폼이 제출 되도록 한다.

이런 식으로 해결 완료!

 

 

참고

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/async_function

https://developer.mozilla.org/ko/docs/Web/API/FormData/FormData

https://reactjs.org/docs/hooks-reference.html#useref