๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

TIL

React_์ด๋ฏธ์ง€ ํŒŒ์ผ ์—…๋กœ๋“œํ•˜๊ธฐ

 

 

๐Ÿ“Œ ๋ฌธ์ œ 

 

์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์„ ํƒํ•˜๊ณ , ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ํ•ด์ฃผ๋Š” ํŽ˜์ด์ง€๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค.

inputBox ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ ๊นŒ์ง€๋Š” ์„ฑ๊ณตํ–ˆ์ง€๋งŒ,

๋ฏธ๋ฆฌ๋ณด๊ธฐ๋กœ ํŽ˜์ด์ง€๊ฐ€ ๋œจ์ง€ ์•Š์•˜๋‹ค.

 

 

 

 

๐Ÿ“Œ ์‹œ๋„ํ•œ ๋ฐฉ๋ฒ•

 

import React, { useState } from 'react';
import Layout from '../components/common/Layout';
import { styled } from 'styled-components';
import Text from '../components/common/Text';
import Button from '../components/common/Button';
import InputBox from '../components/common/InputBox';
import useInput from '../hooks/useInput';
import { useMutation } from 'react-query';
import { uploadPost } from '../api/posts';

function Upload() {
  // ํ…์ŠคํŠธ ๊ด€๋ฆฌ
  const [title, titleHandler] = useInput();
  const [price, priceHandler] = useInput();
  const [content, contentHandler] = useInput();
  const [location, locationHandler] = useInput();

  // ํŒŒ์ผ ๊ด€๋ฆฌ
  const [photo, setPhoto] = useState(null);

  //์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ด€๋ฆฌ
  const [previewUrl, setPreviewUrl] = useState(null);

  const photoChange = (e) => {
    const file = e.target.files;
    setPhoto(file);
    setPreviewUrl(URL.createObjectURL(file));
  }

  const uploadMutation = useMutation(uploadPost, {
    onSuccess: () => {
      alert('์—…๋กœ๋“œ์— ์„ฑ๊ณตํ•˜์…จ์Šต๋‹ˆ๋‹ค.')
    }
  })

  const handleSubmit = (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append('photo', photo);
    formData.append('title', title);
    formData.append('price', price);
    formData.append('content', content);
    formData.append('location', location);

    uploadMutation.mutate(formData);
  }

  return (
    <Layout>
      <PostTitle>์ค‘๊ณ  ๋ฌผํ’ˆ ์˜ฌ๋ฆฌ๊ธฐ</PostTitle>
      <Container>
        <CardPhoto>
          {previewUrl && <img src={previewUrl} alt="Preview" style={{ maxWidth: '100%', maxHeight: '100%' }} />}
          <InputBox type={'file'} onChange={photoChange} accept={'image/*'} />
          <label></label>
        </CardPhoto>
        <form onSubmit={handleSubmit}>
          <UploadTitle>
            <Text fontSize={'25px'} fontWeight={'bold'} color={'#9e7979'}>
              ๊ธ€ ์ œ๋ชฉ
            </Text>
            <InputBox width={'270px'} height={'28px'} shadow={'1px 1px 3px 1px #9e7979'}
              value={title}
              onChange={titleHandler} />
          </UploadTitle>
          <UploadPrice>
            <Text fontSize={'25px'} fontWeight={'bold'} color={'#9e7979'}>
              ๊ฐ€๊ฒฉ
            </Text>
            <InputBox width={'270px'} height={'28px'} shadow={'1px 1px 3px 1px #9e7979'}
              value={price}
              onChange={priceHandler} />
          </UploadPrice>
          <UploadContent>
            <Text fontSize={'25px'} fontWeight={'bold'} color={'#9e7979'}>
              ๋ฌผํ’ˆ ์„ค๋ช…
            </Text>
            <InputBox width={'270px'} height={'28px'} shadow={'1px 1px 3px 1px #9e7979'}
              value={content}
              onChange={contentHandler} />
          </UploadContent>
          <UploadLocation>
            <Text fontSize={'25px'} fontWeight={'bold'} color={'#9e7979'}>
              ๊ฑฐ์ฃผ์ง€
            </Text>
            <InputBox width={'270px'} height={'28px'} shadow={'1px 1px 3px 1px #9e7979'}
              value={location}
              onChange={locationHandler} />
          </UploadLocation>
          <div style={{ width: '40%', margin: 'auto' }}>
            <Button width={'100%'} height={'45px'} bc={'#9e7979'} onClick={handleSubmit}>
              <Text fontSize={'22px'} fontWeight={'bold'} color={'#ffffff'}>
                ๊ฒŒ์‹œ๋ฌผ ์˜ฌ๋ฆฌ๊ธฐ
              </Text>
            </Button>
          </div>
        </form>
      </Container>
    </Layout>
  );
}

previewUrl์ด๋ผ๋Š” ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

photoChange ํ•จ์ˆ˜์—์„œ ์ด๋ฏธ์ง€๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค URL.createObjectURL(file)์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฏธ๋ฆฌ๋ณด๊ธฐ URL์„ ์ƒ์„ฑํ•˜๊ณ , previewUrl ์ƒํƒœ์— ์„ค์ •ํ•œ๋‹ค. ๊ทธ ๋‹ค์Œ, previewUrl์ด ์กด์žฌํ•  ๋•Œ์—๋งŒ <img> ์š”์†Œ๊ฐ€ ๋ Œ๋”๋ง๋˜๋„๋ก ์„ค์ •ํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•œ๋‹ค.

 

 

 

๊ทธ๋Ÿฌ๋‚˜, ์˜ค๋ฅ˜๋ฐœ์ƒ .. !!

๋ฏธํ•ด๊ฒฐ. ์—๋Ÿฌ์ฝ”๋“œ

 

๐Ÿ“Œ ์›์ธ

 

createObjectURL ํ•จ์ˆ˜๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ํŒŒ์ผ ๊ฐ์ฒด๋ฅผ URL๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ตœ์‹  ๋ฒ„์ „์˜ Chrome ๋ฐ Firefox์—์„œ๋Š” ์ด ํ•จ์ˆ˜์˜ ์‚ฌ์šฉ์ด ์ œํ•œ๋˜์—ˆ๋‹ค...?? 

๋Œ€์‹ ์—, ์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ์œ„ํ•ด ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•œ ํ›„์—๋Š” FileReader ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŒŒ์ผ์„ ์ฝ๊ณ , ๋ฐ์ดํ„ฐ URL์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

๐Ÿ“Œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

 

import React, { useState } from 'react';
import Layout from '../components/common/Layout';
import { styled } from 'styled-components';
import Text from '../components/common/Text';
import Button from '../components/common/Button';
import InputBox from '../components/common/InputBox';
import useInput from '../hooks/useInput';
import { useMutation } from 'react-query';
import { uploadPost } from '../api/posts';

function Upload() {
  // ํ…์ŠคํŠธ ๊ด€๋ฆฌ
  const [title, titleHandler] = useInput();
  const [price, priceHandler] = useInput();
  const [content, contentHandler] = useInput();
  const [location, locationHandler] = useInput();

  // ํŒŒ์ผ ๊ด€๋ฆฌ
  const [photo, setPhoto] = useState(null);

  //์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ด€๋ฆฌ
  const [previewUrl, setPreviewUrl] = useState(null);

  const photoChange = (e) => {
    const file = e.target.files[0];
    setPhoto(file);

    const reader = new FileReader();
    reader.onload=() => {
      setPreviewUrl(reader.result);
    };
    reader.readAsDataURL(file);
  };

  const uploadMutation = useMutation(uploadPost, {
    onSuccess: () => {
      alert('์—…๋กœ๋“œ์— ์„ฑ๊ณตํ•˜์…จ์Šต๋‹ˆ๋‹ค.')
    }
  })

  const handleSubmit = (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append('photo', photo);
    formData.append('title', title);
    formData.append('price', price);
    formData.append('content', content);
    formData.append('location', location);

    uploadMutation.mutate(formData);
  }

  return (
    <Layout>
      <PostTitle>์ค‘๊ณ  ๋ฌผํ’ˆ ์˜ฌ๋ฆฌ๊ธฐ</PostTitle>
      <Container>
        <CardPhoto>
          {previewUrl && <img src={previewUrl} alt="Preview" style={{ maxWidth: '100%', maxHeight: '100%' }} />}
          <InputBox type={'file'} onChange={photoChange} accept={'image/*'} />
        </CardPhoto>
        <form onSubmit={handleSubmit}>
          <UploadTitle>
            <Text fontSize={'25px'} fontWeight={'bold'} color={'#9e7979'}>
              ๊ธ€ ์ œ๋ชฉ
            </Text>
            <InputBox width={'270px'} height={'28px'} shadow={'1px 1px 3px 1px #9e7979'}
              value={title}
              onChange={titleHandler} />
          </UploadTitle>
          <UploadPrice>
            <Text fontSize={'25px'} fontWeight={'bold'} color={'#9e7979'}>
              ๊ฐ€๊ฒฉ
            </Text>
            <InputBox width={'270px'} height={'28px'} shadow={'1px 1px 3px 1px #9e7979'}
              value={price}
              onChange={priceHandler} />
          </UploadPrice>
          <UploadContent>
            <Text fontSize={'25px'} fontWeight={'bold'} color={'#9e7979'}>
              ๋ฌผํ’ˆ ์„ค๋ช…
            </Text>
            <InputBox width={'270px'} height={'28px'} shadow={'1px 1px 3px 1px #9e7979'}
              value={content}
              onChange={contentHandler} />
          </UploadContent>
          <UploadLocation>
            <Text fontSize={'25px'} fontWeight={'bold'} color={'#9e7979'}>
              ๊ฑฐ์ฃผ์ง€
            </Text>
            <InputBox width={'270px'} height={'28px'} shadow={'1px 1px 3px 1px #9e7979'}
              value={location}
              onChange={locationHandler} />
          </UploadLocation>
          <div style={{ width: '40%', margin: 'auto' }}>
            <Button width={'100%'} height={'45px'} bc={'#9e7979'} onClick={handleSubmit}>
              <Text fontSize={'22px'} fontWeight={'bold'} color={'#ffffff'}>
                ๊ฒŒ์‹œ๋ฌผ ์˜ฌ๋ฆฌ๊ธฐ
              </Text>
            </Button>
          </div>
        </form>
      </Container>
    </Layout>
  );
}

export default Upload;

 

 

'TIL' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

์›นํŽ˜์ด์ง€ ๋žœ๋”๋ง ใƒป Restful API  (0) 2023.07.19
ํ”„๋กœ์ ํŠธ ํšŒ๊ณ ๋ก  (0) 2023.07.06
JSON  (0) 2023.05.02
React_action creators, action values  (0) 2023.05.02
React_useDispatch, useSelector  (0) 2023.04.29