오늘의 목적은 React 프론트엔드에 특정한 JSON 형식의 파일을 업로드 하고,
이 JSON 파일 내부에 있는 정보를 통해서 프론트엔드에 어떠한 “값”들을 저장할 겁니다.
이를 위해서는 JSON 업로드 창을 구현해야 할 것이며
업로드 된 JSON 파일 정보에서 특정한 값들만을 꺼낼 수 있도록 파싱을 하는 방법도 필요하겠네요.
바로 시작하죠.
우선은 위과 같은 코드부터 시작을 합시다.
위 코드는 input 의 type 이 file 입니다.
그리고, .json 파일만을 업로드 가능하게 하는 input 창이죠.
위 코드만 댕그러니 출력을 하면 위와 같은 모양이 됩니다.
이거를 적절한 코드로 꾸며보겠습니다.
요렇게 해보고자 합니다.
파일 업로드를 위한 input창과 label을 같이 넣어두는 거죠.
이때 input 창 자체는 실제로 화면에 나타나지 않게 display를 none으로 했습니다.
그리고 isDraggingOver 상태에 따라서 문구가 달라지게 설정을 해줍니다.
import React, { useState, useCallback } from "react";
const Test = () => {
//여기서 드래그 상태를 체크할 거임... 파일 드래그가 된 상태인지, 아닌 상태인지!
const [isDraggingOver, setIsDraggingOver] = useState(false);
//파일을 드래그 하자마자 열리는데, 이걸 통해서 드래그 중에는 파일이 열리지 않도록 막을 것이다.
const handleDragOver = useCallback((e) => {
e.preventDefault();
}, []);
//영역 안으로 파일을 드래그 한 상태라면? 우선은 내부에 발생하는 이벤트는 막는다. 드래그에서 뗄 때 파일을 업로드 할 거니까~ 대신 이쁘게 하기 위해서 isDraggingOver 을 True로 바꾼다!
const handleDragEnter = useCallback((e) => {
e.preventDefault();
setIsDraggingOver(true); // 드래그 시작 상태로 변경
}, []);
//영역 밖으로 드래그 중인 게 나간다면? 파일이 열리지 않도록 여기도 이벤트는 막는다. 그리고 나갔으니까 드래그 체크 변수를 False로 변경한다!
const handleDragLeave = useCallback((e) => {
e.preventDefault();
setIsDraggingOver(false); // 드래그 종료 상태로 변경
}, []);
//영역 내에서 드래그 중이던 파일을 놓았을 때 발동될 거다. 드래그 상태를 초기화 하고, 메시지를 호출할 거다.
const handleDrop = useCallback((e) => {
e.preventDefault();
setIsDraggingOver(false); // 드롭 후 드래그 상태 초기화
const droppedFile = e.dataTransfer.files[0]; // 전송된 파일들 중의 0번째 파일의 정보를 뜻함, 업로드가 됐다면 True가 된다는 뜻.
if (droppedFile && droppedFile.type === "application/json") {
alert("JSON 파일 드랍에 성공했습니다!");
} else if (droppedFile) {
alert("JSON 파일만 업로드해주세요.");
}
}, []);
return (
<>
>
);
};
export default Test;
그리고 위와 같이 거대한 div 내부에 앞서 만든 input 과 label을 담습니다.
그리고 이 div 에는 “드래그 드랍” 설정을 해줍니다.
드래그 드랍 설정을 위해 작동하는 동작은 총 4가지가 있습니다.
.upload-box {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
border: 2px dashed #ccc;
border-radius: 10px;
cursor: pointer;
width: 800px;
margin-bottom: 20px;
transition: all 0.2s ease-in-out; /* 부드러운 효과를 위해 transition 추가 */
}
.upload-box:hover {
border-color: #888;
}
/* 드래그 중 스타일 */
.upload-box.drag-over {
border-style: solid; /* 점선 -> 실선 */
border-color: #007bff; /* 강조 색상 */
background-color: #f8f8f8; /* 배경색 변경 */
padding: 50px 20px; /* 패딩 증가 */
transform: scale(1.05); /* 살짝 확대 효과 */
}
.upload-label {
font-size: 16px;
color: #555;
text-align: center;
margin-bottom: 10px;
transition: color 0.2s ease-in-out; /* 문구 색상 변화 transition */
}
.upload-box.drag-over .upload-label {
color: #333; /* 드래그 중 문구 색상 변경 */
font-size: 18px; /* 드래그 중 문구 크기 변경 */
}
.template-btn {
padding: 10px 15px;
background-color: #f0f0f0;
border: 1px solid #ccc;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
}
.template-btn:hover {
background-color: #e0e0e0;
}
여기서 위와 같은 CSS 디자인을 입혀서 보겠습니다.
어떻게 나타날까요?
위와 같이 전체적으로 JSON 파일 드래그 앤 드롭 또는 클릭! 이라는 메시지가 있는 창이 나타납니다.
그리고 이곳에 파일을 드래그 하면 upload-box.drag-over 상태가 적용이 되게 됩니다.
//영역 내에서 드래그 중이던 파일을 놓았을 때 발동될 거다. 드래그 상태를 초기화 하고, 메시지를 호출할 거다.
const handleDrop = useCallback((e) => {
e.preventDefault();
setIsDraggingOver(false); // 드롭 후 드래그 상태 초기화
const droppedFile = e.dataTransfer.files[0]; // 전송된 파일들 중의 0번째 파일의 정보를 뜻함, 업로드가 됐다면 True가 된다는 뜻.
if (droppedFile && droppedFile.type === "application/json") {
alert("JSON 파일 드랍에 성공했습니다!");
} else if (droppedFile) {
alert("JSON 파일만 업로드해주세요.");
}
}, []);
방금 전에는 handleDrop 이 실제로 파일을 놓게 되면 작동하는 함수였습니다.
그런데 이 포스팅의 목적은 업로드한 JSON 파일을 파싱해서, 내가 원하는 값을 사용하는 것이 목적입니다.
지금은 파일 업로드가 성공하면 alter(“…”) 이 작동하지만…
실제로 작동을 시킬 함수를 만들 필요가 있습니다.
//업로드한 JSON 파일을 놓게 되면 여기가 바뀔 거임!
const [gojo, setGojo] = useState("");
const [megumi, setMegumi] = useState("");
이를 위해서 요딴 코드와…
고죠 사토루 : {gojo}
후시구로 메구미 : {megumi}
요딴 필드를 추가해봤습니다.
그럼 요렇게 아직 아무런 대사가 없습니다.
json 파일을 업로드해서,setGojo 와 setMegumi 를 발동해보죠.
// 드롭 이벤트 처리 함수
const handleDrop = useCallback((e) => {
e.preventDefault();
setIsDraggingOver(false); // 드롭 후 드래그 상태 초기화
const droppedFile = e.dataTransfer.files[0]; // 드롭된 파일 가져오기
if (droppedFile && droppedFile.type === "application/json") {
processJsonFile(droppedFile, "gojo"); // JSON 파일 처리 함수 호출
} else if (droppedFile) {
alert("JSON 파일만 업로드해주세요.");
}
}, []);
요런 식으로 사용할 계획입니다.
앞서 alert 으로 그냥 성공했어요~ 메시지만 보냈는데 실제 어떤 함수가 동작하는 거죠.
// JSON 파일 읽고 특정 key와 value를 가져오는 함수
const processJsonFile = (file, targetKey) => {
const reader = new FileReader();
reader.onload = (event) => {
try {
const jsonData = JSON.parse(event.target.result); // JSON 파싱
console.log(jsonData); // 전체 JSON 데이터 확인
// 특정 key와 value 가져오기
if (jsonData[targetKey] !== undefined) {
alert(`Key: ${targetKey}, Value: ${jsonData[targetKey]}`);
} else {
alert(`Key "${targetKey}"를 찾을 수 없습니다.`);
}
} catch (error) {
console.error("JSON 파싱 에러:", error);
alert("유효하지 않은 JSON 파일입니다.");
}
};
reader.onerror = () => {
console.error("파일 읽기 실패");
alert("파일을 읽는 중 오류가 발생했습니다.");
};
reader.readAsText(file); // 파일을 텍스트로 읽기
};
실제로 동작을 할 어떤 함수입니다.
우선은 이대로 한 번 사용을 해볼까요?
{
"gojo": "료요키 텐카이!",
"megumi": "후루베 유라유라!"
}
위와 같은 json 파일을 업로드 하면, 이렇게 나옵니다~
제가 handleDrop 내부에서 작동시킨 processJsonFile 에다가 “gojo” 를 넣었기 때문이죠.
그럼 processJsonFile 의 구조를 좀 더 변경하겠습니다.
// JSON 파일 읽고 특정 key와 value를 가져오는 함수
const processJsonFile = (file, targetKey) => {
const reader = new FileReader();
reader.onload = (event) => {
try {
const jsonData = JSON.parse(event.target.result); // JSON 파싱
console.log(jsonData); // 전체 JSON 데이터 확인
// 특정 key와 value 가져오기
if (jsonData[targetKey] !== undefined) {
setGojo(jsonData[targetKey]);
} else {
alert(`Key "${targetKey}"를 찾을 수 없습니다.`);
}
} catch (error) {
console.error("JSON 파싱 에러:", error);
alert("유효하지 않은 JSON 파일입니다.");
}
};
reader.onerror = () => {
console.error("파일 읽기 실패");
alert("파일을 읽는 중 오류가 발생했습니다.");
};
reader.readAsText(file); // 파일을 텍스트로 읽기
};
이런 식으로 setGojo를 넣었습니다.
그럼 다시 한 번 json을 업로드 하면?
오오, 대사가 발동되네요!
나쁘지 않습니다.
그럼 메구미의 대사도 발동하려면 어떻게 조작할까요?
//고조가 말한다.
const sadGojo = (file) => {
const reader = new FileReader();
const targetKey = "gojo";
reader.onload = (event) => {
try {
const jsonData = JSON.parse(event.target.result); // JSON 파싱
console.log(jsonData); // 전체 JSON 데이터 확인
// 특정 key와 value 가져오기
if (jsonData[targetKey] !== undefined) {
setGojo(jsonData[targetKey]);
} else {
alert(`Key "${targetKey}"를 찾을 수 없습니다.`);
}
} catch (error) {
console.error("JSON 파싱 에러:", error);
alert("유효하지 않은 JSON 파일입니다.");
}
};
reader.onerror = () => {
console.error("파일 읽기 실패");
alert("파일을 읽는 중 오류가 발생했습니다.");
};
reader.readAsText(file); // 파일을 텍스트로 읽기
};
//메구미가 말한다.
const sadMegumi = (file) => {
const reader = new FileReader();
const targetKey = "megumi";
reader.onload = (event) => {
try {
const jsonData = JSON.parse(event.target.result); // JSON 파싱
console.log(jsonData); // 전체 JSON 데이터 확인
// 특정 key와 value 가져오기
if (jsonData[targetKey] !== undefined) {
setMegumi(jsonData[targetKey]);
} else {
alert(`Key "${targetKey}"를 찾을 수 없습니다.`);
}
} catch (error) {
console.error("JSON 파싱 에러:", error);
alert("유효하지 않은 JSON 파일입니다.");
}
};
reader.onerror = () => {
console.error("파일 읽기 실패");
alert("파일을 읽는 중 오류가 발생했습니다.");
};
reader.readAsText(file); // 파일을 텍스트로 읽기
};
저는 이런 식으로 각각의 함수를 만드는 방법으로 관리를 해봤습니다.
이런 방식으로 사용하기 위해서는…
//영역 내에서 드래그 중이던 파일을 놓았을 때 발동될 거다. 드래그 상태를 초기화 하고, 메시지를 호출할 거다.
const handleDrop = useCallback((e) => {
e.preventDefault();
setIsDraggingOver(false); // 드롭 후 드래그 상태 초기화
const droppedFile = e.dataTransfer.files[0]; // 전송된 파일들 중의 0번째 파일의 정보를 뜻함, 업로드가 됐다면 True가 된다는 뜻.
if (droppedFile && droppedFile.type === "application/json") {
sadGojo(droppedFile);
sadMegumi(droppedFile);
} else if (droppedFile) {
alert("JSON 파일만 업로드해주세요.");
}
}, []);
위와 같이 handleDrop을 변경하면 되겠네요.
업로드가 성공하면 차례차례 필요한 함수들이 실행이 되는 거죠.
이렇게 잘 되는 것을 확인했습니다.
이제 위 방법을 활용해서 json 파일을 업로드 하고, 파싱해서 활용하는 방안을 모색해보세요.
다음에도 또 비루한 주제를 가지고 포스팅을 해보겠습니다.
여기까지 봐주신 분들 정말 감사합니다.^^