[React] 카카오 Map API - Polyline Json 업로드

또여·2021년 8월 26일
0

React 프로젝트

목록 보기
9/20
post-custom-banner

구글의 Timeline 데이터는 Json 파일인데 이걸 멀티로 업로드하는 기능이 필요한데,
화면을 따로 빼기보다는 dialog로 팝업창 띄우는 방식으로 해보았다

0. 결과물

material-ui에 Dialog를 활용했고, 텍스트와 버튼을 추가하고 업로드하는 영역도 추가된 모습

1. Upload.js

https://material-ui.com/components/dialogs/#dialog
에 있는 부분을 그대로 붙여넣음

100번 라인에 JsonUpload라는 컴포넌트가 실제 업로드하고 업로드된 데이터를 눈으로 보는 부분이 되겠다

여기는 업로드 버튼을 눌렀을 때 타는 로직인데 중복된 이름으로 업로드 된것도 체크해줘야하고, 확장자가 json이 아닌경우도 걸러주면 좋을것 같다
이미지 업로드하는 부분과 똑같이 처리하였다

import React, { useEffect, useState } from 'react';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import Slide from '@material-ui/core/Slide';
import JsonUpload from '../../../utils/JsonUpload'
import axios from 'axios'


const Transition = React.forwardRef(function Transition(props, ref) {
  return <Slide direction="up" ref={ref} {...props} />
})

function TlUploadPage() {
  const [open, setOpen] = useState(false)
  const [Files, setFiles] = useState([])
  const [FilePath, setFilePath] = useState([])

  useEffect(() => {
    if(FilePath) {
      console.log(' Path >>', FilePath)
    }
  }, [FilePath])

  const handleClickOpen = () => {
    setOpen(true)
  }

  const handleClear = () => {
    setFiles([])
  }

  const handleClose = () => {
    setOpen(false)
  }

  const handleUpload = () => {
    if(Files.length === 0) return

    for(let i = 0; i < Files.length; i++){
      for(let j = 0; j < Files.length; j++){
        if(Files[i].name === Files[j].name && i !== j){
          alert(`${Files[i].name} 파일이 중복됩니다!`)
          return
        }
      }
    }

    let formData = new FormData()
    for(let i = 0; i < Files.length; i++){
        formData.append("file", Files[i])
    }
    const config = {
        headers: {
            'Content-Type': 'multipart/form-data'
        }
    }
    axios.post('/api/polyline/dataupload', formData, config)
    .then(response => {
      if(response.data.success){
        let newPath = []
        response.data.files.map((cur) => {
          newPath.push(cur.path)
        })
        setFilePath(newPath)
        setOpen(false)
    } else{
        alert('파일 업로드 실패!')
    }
    })
  }

  const onSetFiles = (files) => {
    setFiles(files)
  }

  return (
    <div style={{padding: '10px 15px'}}>
      <div onClick={handleClickOpen}>
        Data Upload
      </div>
      <Dialog
        open={open}
        TransitionComponent={Transition}
        keepMounted
        onClose={handleClose}
        aria-labelledby="alert-dialog-slide-title"
        aria-describedby="alert-dialog-slide-description"
      >
        <DialogTitle id="alert-dialog-slide-title">
          Json 파일을 업로드하세요!
        </DialogTitle>
        <DialogContent>
          {/* <DialogContentText id="alert-dialog-slide-description">
          Text~~
          </DialogContentText> */}
            <JsonUpload
              initFiles={Files}
              updateFiles={onSetFiles}/>
        </DialogContent>
        <DialogActions>
          <Button onClick={handleClear} color="primary">
            초기화
          </Button>
          <Button onClick={handleClose} color="primary">
            취소
          </Button>
          <Button onClick={handleUpload} color="primary" 
            disabled={Files.length > 0 ? false:true}>
            업로드
          </Button>
        </DialogActions>
      </Dialog>
    </div>
  )
}

export default TlUploadPage

2. jsonUpload.js

지난 이미지업로드와 비슷하게, dropHandler에서 처리한다
붙인 데이터를 push해서 setState 해주고 상위 props로 올린다!


DeleteIcon을 추가해서 눌렀을 때, 파일에서 없애주고 마찬가지로 상위 props로 변경된 파일을 갱신해준다

import React, { useEffect, useState } from 'react'
import Dropzone from 'react-dropzone'
import { Icon } from 'antd'
import axios from 'axios'
import DeleteIcon from '@material-ui/icons/Delete';


function FileUpload(props) {
    const [Files, setFiles] = useState([])

    useEffect(() => {
        setFiles(props.initFiles)
    }, [props.initFiles])

    const dropHandler = (files) => {
        let newFiles = [...Files]
        files.map((cur) => {
            newFiles.push(cur)
        })
        setFiles(newFiles)
        props.updateFiles(newFiles)
    }

    return (
        <div style={{display:'flex', justifyContent:'space-between'}}>
            <Dropzone 
                onDrop={dropHandler}
                multiple>
                {({getRootProps, getInputProps}) => (
                    <section>
                        <div style={{
                            width:200, height: 140, border:'1px solid lightgray',
                            display:'flex', alignItems: 'center', justifyContent:'center'
                            }}
                            {...getRootProps()}>
                            <input {...getInputProps()} />
                            <Icon type="plus" style={{ fontSize:'2rem'}}/>
                        </div>
                    </section>
                )}
            </Dropzone>
            <div style={{ width:'400px', height: '140px', overflowY:'auto'}}>
                {Files && Files.map((cur, index) => (
                    <div style={{margin: '0px 10px'}} key={index}>
                        {`# ${index+1} - ${cur.name}`}
                        <div style={{display:'inline-block', marginLeft: '5px'}}>
                            <DeleteIcon 
                                    style={{verticalAlign:'middle'}}
                                    onClick={() => {
                                        setFiles(Files.filter((file) => file !== cur))
                                        props.updateFiles(Files.filter((file) => file !== cur))
                                    }}/>
                        </div>
                    </div>
                ))}
            </div>
        </div>
    )
}

export default FileUpload
profile
기록 열심히하는 개발자인척
post-custom-banner

0개의 댓글