파일 수정하기 안 됨…………………………..
글 내용 작성 후 post 로 서버에 보내주기(백단에선 update 쿼리문)
뭐가 문제일까? 계속 board_num 에 null 이 들어온다 ,, 백엔드 문제인지 프론트 문제인지 모르겠다 ,,,
미치겠다~~
—결국 해냄 —
수정 전 코드
import { useState } from "react";
import style from "../css/Write.module.css";
import { Link } from "react-router-dom";
import Footer from "../Final/Footer/Footer";
import main_logo from "../images/main_logo.png";
import axios from "axios";
import { useNavigate } from "react-router-dom";
const Modify = () => {
// 상태 변수 정의
const [title, setTitle] = useState("");
const [location, setLocation] = useState("");
const [price, setPrice] = useState("");
const [text, setText] = useState("");
const [file, setFile] = useState(null);
const [listFile, setListfile] = useState();
const navigate = useNavigate();
// input 값 변경 시, 상태 변수 업데이트
const handleTitleChange = (e) => {
setTitle(e.target.value);
};
const handleLocationChange = (e) => {
setLocation(e.target.value);
};
const [fileDataList, setFileDataList] = useState(); // 서버에 업로드 된 파일 리스트
var fileList = []; // 업로드 할 파일 리스트 저장
const onSaveFiles = (e) => {
const updatefiles = Array.prototype.slice.call(e.target.files); // 파일 이름을 배열 형태로 저장하는 객체
console.log("updatefiles => " + updatefiles);
updatefiles.forEach((updatefiles) => {
console.log("bbb :" + updatefiles);
fileList.push(updatefiles); // 배열에 push
});
setListfile(fileList);
};
const onFileUpload = (e) => {
const formData = new FormData(); // <form></form> 형식의 데이터를 전송하기 위해 주로 사용.
console.log("fileList=>" + listFile);
listFile.forEach((file) => {
formData.append("updatefiles", file);
});
console.log(formData);
if (listFile.length === 0) {
alert("상품 사진을 하나 이상 등록해 주세요.");
}
console.log("id : " + sessionStorage.getItem("id"));
console.log("title : " + document.getElementById("title").value);
console.log("location : " + document.getElementById("location").value);
console.log("price : " + document.getElementById("price").value);
console.log("content : " + document.getElementById("content").value);
var boardnum = 0;
axios
.post("/updateboard", {
id: sessionStorage.getItem("id"),
subject: document.getElementById("title").value,
location: document.getElementById("location").value,
price: document.getElementById("price").value,
content: document.getElementById("content").value,
})
.then((res) => {
console.log(res);
console.log(res.data);
console.log("update request");
boardnum = res.data;
})
.catch((e) => {
console.error(e);
})
.then(() => {
axios
.post("/updatefile", formData)
.then((res) => {
console.log("updatefile request");
alert("수정이 완료되었습니다!");
setFileDataList(res.data);
document.location.href = "/home";
})
.catch((e) => {
console.error(e);
});
});
};
const handlePriceChange = (e) => {
setPrice(e.target.value);
};
const handleTextChange = (e) => {
setText(e.target.value);
};
const handleAddressSelect = (e) => {
setFile(e.target.files[0]);
};
const handleFormSubmit = (e) => {
e.preventDefault();
console.log(title, location, price, text, file);
};
return (
<div className="write_page">
<h1 sytle="margin:5px;">
<div className={style.logo_image}>
<a href="/home">
<img src={main_logo} alt="logo" width="300px;" height="75px;" />
</a>
</div>
</h1>
<div className={style.writeContainer}>
<form className={style.form} onSubmit={handleFormSubmit}>
<div className={style["input-box"]}>
<label htmlFor="title">제목</label>
<input
type="text"
id="title"
value={title}
onChange={handleTitleChange}
/>
</div>
<div className={style[("location-wrapper", "input-box")]}>
<label htmlFor="location">거래 지역</label>
<input
type="text"
id="location"
value={location}
onChange={handleLocationChange}
/>
</div>
<div className={(style.fileup, style["input-box"])}>
<label htmlFor="file">파일 업로드</label>
<input type="file" id="file" multiple onChange={onSaveFiles} />
</div>
<div className={(style.price, style["input-box"])}>
<label htmlFor="price">상품 가격(원)</label>
<div className={style.priceup}>
<input
type="number"
id="price"
value={price}
onChange={handlePriceChange}
/>
</div>
</div>
<div className={style["input-box"]}>
<label htmlFor="content">상세 설명</label>
<textarea
id="content"
value={text}
onChange={handleTextChange}
placeholder="상품 소개"
/>
</div>
<div className={style["button-container"]}>
<div id="loginAlert">
<Link to="#" style={{ textDecoration: "none" }}>
<button
className={style["modify-button"]}
onClick={onFileUpload}
>
수정
</button>
</Link>
</div>
<div
id="loginAlert"
onClick={() => {
alert("작성이 취소되었습니다!");
navigate("/home");
}}
>
<Link to="/home" style={{ textDecoration: "none" }}>
<button type="button" className={style["cancel-button"]}>
취소
</button>
</Link>
</div>
</div>
</form>
</div>
<Footer />
</div>
);
};
export default Modify;
수정 후 코드
import { useState } from "react";
import style from "../css/Write.module.css";
import { Link } from "react-router-dom";
import Footer from "../Final/Footer/Footer";
import main_logo from "../images/main_logo.png";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import { useLocation } from "react-router-dom";
const Modify = () => {
//추가 된 코드
const loc = useLocation();
const board_num = loc.state?.data?.num;
console.log(loc, board_num);
// 상태 변수 정의
const [title, setTitle] = useState("");
const [location, setLocation] = useState("");
const [price, setPrice] = useState("");
const [text, setText] = useState("");
const [file, setFile] = useState(null);
const [listFile, setListfile] = useState();
const navigate = useNavigate();
// input 값 변경 시, 상태 변수 업데이트
const handleTitleChange = (e) => {
setTitle(e.target.value);
};
const handleLocationChange = (e) => {
setLocation(e.target.value);
};
const [fileDataList, setFileDataList] = useState(); // 서버에 업로드 된 파일 리스트
var fileList = []; // 업로드 할 파일 리스트 저장
const onSaveFiles = (e) => {
const updatefiles = Array.prototype.slice.call(e.target.files); // 파일 이름을 배열 형태로 저장하는 객체
console.log("updatefiles => " + updatefiles);
updatefiles.forEach((updatefiles) => {
console.log("bbb :" + updatefiles);
fileList.push(updatefiles); // 배열에 push
});
setListfile(fileList);
};
const onFileUpload = (e) => {
const formData = new FormData(); // <form></form> 형식의 데이터를 전송하기 위해 주로 사용.
listFile.forEach((file) => {
formData.append("updatefiles", file);
});
console.log("fileList=>" + listFile);
formData.append("num", document.getElementById("num").value); //추가 된 코드
console.log(formData);
if (listFile.length === 0) {
alert("상품 사진을 하나 이상 등록해 주세요.");
}
console.log("id : " + sessionStorage.getItem("id"));
console.log("title : " + document.getElementById("title").value);
console.log("location : " + document.getElementById("location").value);
console.log("price : " + document.getElementById("price").value);
console.log("content : " + document.getElementById("content").value);
axios
.post("/updateboard", {
num: document.getElementById("num").value, //추가 된 코드
id: sessionStorage.getItem("id"),
subject: document.getElementById("title").value,
location: document.getElementById("location").value,
price: document.getElementById("price").value,
content: document.getElementById("content").value,
})
.then((res) => {
console.log("update request");
axios
.post("/updatefile", formData)
.then((res) => {
console.log("updatefile request");
alert("수정이 완료되었습니다!");
// setFileDataList(res.data);
document.location.href = "/home";
})
.catch((e) => {
console.error(e);
});
})
.catch((e) => {
console.error(e);
});
};
const handlePriceChange = (e) => {
setPrice(e.target.value);
};
const handleTextChange = (e) => {
setText(e.target.value);
};
const handleAddressSelect = (e) => {
setFile(e.target.files[0]);
};
const handleFormSubmit = (e) => {
e.preventDefault();
console.log(title, location, price, text, file);
};
return (
<div className="write_page">
<h1 sytle="margin:5px;">
<div className={style.logo_image}>
<a href="/home">
<img src={main_logo} alt="logo" width="300px;" height="75px;" />
</a>
</div>
</h1>
<div className={style.writeContainer}>
<form className={style.form} onSubmit={handleFormSubmit}>
<input type="hidden" id="num" value={board_num} /> //추가 된 코드
<div className={style["input-box"]}>
<label htmlFor="title">제목</label>
<input
type="text"
id="title"
value={title}
onChange={handleTitleChange}
/>
</div>
<div className={style[("location-wrapper", "input-box")]}>
<label htmlFor="location">거래 지역</label>
<input
type="text"
id="location"
value={location}
onChange={handleLocationChange}
/>
</div>
<div className={(style.fileup, style["input-box"])}>
<label htmlFor="file">파일 업로드</label>
<input type="file" id="file" multiple onChange={onSaveFiles} />
</div>
<div className={(style.price, style["input-box"])}>
<label htmlFor="price">상품 가격(원)</label>
<div className={style.priceup}>
<input
type="number"
id="price"
value={price}
onChange={handlePriceChange}
/>
</div>
</div>
<div className={style["input-box"]}>
<label htmlFor="content">상세 설명</label>
<textarea
id="content"
value={text}
onChange={handleTextChange}
placeholder="상품 소개"
/>
</div>
<div className={style["button-container"]}>
<div id="loginAlert">
<Link to="#" style={{ textDecoration: "none" }}>
<button
className={style["modify-button"]}
onClick={onFileUpload}
>
수정
</button>
</Link>
</div>
<div
id="loginAlert"
onClick={() => {
alert("작성이 취소되었습니다!");
navigate("/home");
}}
>
<Link to="/home" style={{ textDecoration: "none" }}>
<button type="button" className={style["cancel-button"]}>
취소
</button>
</Link>
</div>
</div>
</form>
</div>
<Footer />
</div>
);
};
export default Modify;
board_num 으로 update 를 해줘야하는데 자꾸 board_num 에 null 값이 들어가서 update 가 안 됐다 ,, 그래서 detail 에서 board_num 을 받아오도록 설계를 수정 했다 …
그리고 RequestParam 으로 updatefiles 를 받아주도록 백엔드도 수정했다.
추가 된 코드
const loc = useLocation();
const board_num = loc.state?.data?.num;
formData.append("num", document.getElementById("num").value);
num: document.getElementById("num").value,
detail.js
import { Link } from "react-router-dom";
import profile from "../../images/image-07.jpg";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import axios from "axios";
const DetailContentExplain = ({ board }) => {
const navigate = useNavigate();
const ContentExplainStyle = {
margin: "0 auto 30px auto",
padding: "20px 0 0 0",
height: "40vh",
display: "block",
width: "1300px",
};
// 게시자 프로필을 감싸는 div의 스타일
const ContentExplainUserStyle = {
display: "flex",
overflow: "hidden",
background: "#BBD6FF",
borderBottom: "0px solid #BBD6FF ",
borderRadius: "20px 20px 0 0",
padding: "10px",
alignItems: "center",
justifyContent: "flex-start",
boxSizing: "border-box",
};
const UserProfile = {
width: "40px",
height: "40px",
borderRadius: "70%",
cursor: "pointer",
};
const ProfilePtag = {
justifyContent: "center",
align: "center",
width: "100px",
height: "0px",
color: "#ffffff ",
cursor: "pointer",
lineHeight: "0px",
};
// 게시자의 설명문을 감싸는 div의 스타일
const ContentExplainAreaStyle = {
border: "1px solid #BBD6FF ",
borderTop: "1px solid #BBD6FF ",
height: "80%",
borderRadius: "0 0 20px 20px",
boxSizing: "border-box",
};
const ExplainPtag = {
margin: "20px",
fontSize: "1rem",
textAlign: "left",
};
const ButtonWrap = {
textAlign: "right",
margin: "20px 0 0 ",
};
const Button = {
background: "#BBD6FF",
border: "none",
color: "white",
width: "90px",
height: "30px",
borderRadius: "3px",
marginLeft: "10px",
};
const Buttonmdf = {
background: "white",
border: "1px solid black",
outline: "0",
color: "black",
width: "90px",
height: "30px",
borderRadius: "3px",
};
const modifyHandler = (e, board) => {
console.log(board);
/*
{
"num": 1,
"id": "admin",
"subject": "ㄷㅈㄹㄷㅈ",
"location": "ㄹㄷㅈ",
"content": "ㅈㅂㅇㅈㅂ",
"price": 321312,
"addcartcount": 0,
"viewcount": 13,
"board_date": "2023-06-25"
}
*/
navigate("/modify", { state: { data: board } });
};
const handeldelete = () => {
axios
.post("/board_del", {
num: board.num,
})
.then((res) => {
axios
.post("/file_del", {
board_num: board.num,
})
.then((res) => {
if (res.data) {
alert("삭제완료!");
document.location.href = "/home";
}
})
.catch((e) => {
console.error(e);
});
});
};
return (
<div style={ContentExplainStyle}>
<div style={ContentExplainUserStyle}>
<img src={profile} style={UserProfile} alt="" />
<p style={ProfilePtag}>
<b>{board.id}</b>
</p>
</div>
<div style={ContentExplainAreaStyle}>
<h4 style={{ margin: "20px", textAlign: "left" }}>{board.subject}</h4>
<p style={ExplainPtag}>{board.content}</p>
</div>
<div style={ButtonWrap}>
{/* <Link to="/modify"> */}
<button
className="Buttonmdf"
style={Buttonmdf}
onClick={(e) => modifyHandler(e, board)}
>
수정
</button>
{/* </Link> */}
<button
className="Button"
style={Button}
value="삭제"
id={board.num}
onClick={handeldelete}
>
삭제
</button>
</div>
</div>
);
};
export default DetailContentExplain;
사실 모든 구조를 내가 설계했다면 조금 더 쉽게 했을 것 같은데...
남이 한 코드를 수정하다보니 이게 왜 이건지.. 이건 뭔지 해석하고 알아보는데에 시간이 오래 걸렸던 것 같다 .
그래서 form 은 써먹지도 못 하고 props 로 얼렁뚱땅 돌아는가게 수정이 된 것 같은데...
진짜 리액트 너무 어렵다.....
delete 는 handledelete 함수를 써서 api 요청 > 백단에서 delete from~ 쿼리 > 서버에서 board 를 리턴 하게 설계했다! 대신 DB 를 file, board 를 나눠서 설계 했기 때문에 file 에 있는 데이터도 삭제하게끔 해줬다,, 뭔가 더 효율적인 방식이 있을 것 같지만 난 그렇게 했다!