Frontend Study
React _ 미니프로젝트#3 마무리
jimmmy_jin
2025. 1. 5. 10:45
마무리 하는 과정에서 다양한 에러를 마주했다.
많은 시간을 썼다.
백엔드는 건드리지도 않았는데 아래의 코드를 진행하면 백엔드 서버가 꺼지고
에러가 발생했다. 아무래도 프론트에서 내가 뭔가 실수를 해서 발생한 오류 같은데
데이터는 올바르게 전송되고 백엔드에서도 올바르게 받아지길래 에러를 살짝 조정했다.
아무래도 백엔드에서 파일을 읽고 쓰는 곳에서 문제가 있었던 듯 하다.
아래는 수정된 백엔드 코드이다.
app.post("/orders", async (req, res) => {
try {
const orderData = req.body.order;
if (!orderData || !orderData.items || orderData.items.length === 0) {
return res.status(400).json({ message: "Missing order items." });
}
const customer = orderData.customer;
if (
!customer ||
!customer.email ||
!customer.email.includes("@") ||
!customer.name ||
customer.name.trim() === "" ||
!customer.street ||
customer.street.trim() === "" ||
!customer["postal-code"] ||
customer["postal-code"].trim() === "" ||
!customer.city ||
customer.city.trim() === ""
) {
return res.status(400).json({
message: "Missing or invalid customer data.",
});
}
const newOrder = {
...orderData,
id: (Math.random() * 1000).toFixed(0),
};
// Read and update orders.json
let allOrders = [];
try {
const orders = await fs.readFile("./data/orders.json", "utf8");
if (orders.trim() !== "") {
allOrders = JSON.parse(orders);
}
} catch (error) {
if (error.code !== "ENOENT") {
console.error("Error reading orders.json:", error.message);
throw error;
}
console.log("orders.json 파일이 없으므로 새로 생성합니다.");
}
그리고 프론트에서는 아래와 같이 코드를 고쳐줬다.
페이지를 사용하지 않고 모달을 사용하기 때문에
모달의 상태를 받아서 모달을 띄워준다.
그래서 쉐어하고 있는 모달의 상태가 있고
http와의 소통을 하고있는 hook함수를 사용하고 있다.
post를 보낼때 header와 body를 결합하는 방법을
아래와 같은 방식으로 했다.
hook에는 body 부분을 data로 따로 받아서 처리했다
const requestConfig = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
};
function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
const customerData = Object.fromEntries(formData.entries());
sendRequest(
JSON.stringify({
order: {
items: cartCtx.items,
customer: customerData,
},
})
);
}
const sendRequest = useCallback(
async function sendRequest(data) {
setIsLoading(true);
try {
const resData = await sendHttpRequest(url, { ...config, body: data });
setData(resData);
} catch (error) {
setError(error.message || "Something went wrong, please try again.");
}
setIsLoading(false);
},
[url, config]
);
확실히 아직 hook을 다루는 능력이 많이 부족하다.
이제 이 이후로 배울 것은 Redux 인데 아마 위와 같은 과정을 다루는
느낌인데 해당 과정을 하면서 좀 더 이해해봐야겠다.
아래는 전체 코드이다.
1. useHttp
import { useState, useEffect, useCallback } from "react";
async function sendHttpRequest(url, config) {
const response = await fetch(url, config);
const resData = await response.json();
if (!response.ok) {
throw new Error(resData.message || "Something went wrong, please try again.");
}
return resData;
}
export default function useHttp(url, config, initialData) {
const [data, setData] = useState(initialData);
const [error, setError] = useState();
const [isLoading, setIsLoading] = useState(false);
function clearData() {
setData(initialData);
}
const sendRequest = useCallback(
async function sendRequest(data) {
setIsLoading(true);
try {
const resData = await sendHttpRequest(url, { ...config, body: data });
setData(resData);
} catch (error) {
setError(error.message || "Something went wrong, please try again.");
}
setIsLoading(false);
},
[url, config]
);
useEffect(() => {
if ((config && (config.method === "GET" || !config.method)) || !config) {
sendRequest();
}
}, [sendRequest, config]);
return {
data,
error,
isLoading,
sendRequest,
clearData,
};
}
2. checkout.jsx
import { useContext } from "react";
import CartContext from "../store/CartContext";
import Modal from "./Modal";
import { currencyFormatter } from "../utils/formatting";
import Input from "./UI/Input";
import Button from "./UI/Button";
import UserProgressContext from "../store/UserProgressContext";
import useHttp from "../hooks/useHttp";
import Error from "./Error";
const requestConfig = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
};
export default function Checkout() {
const cartCtx = useContext(CartContext);
const useProgressCtx = useContext(UserProgressContext);
const cartTotal = cartCtx.items.reduce((acc, item) => acc + item.price * item.quantity, 0);
const {
data,
isLoading: isSending,
error,
sendRequest,
clearData,
} = useHttp("http://localhost:3000/orders", requestConfig);
function handleCloseCheckout() {
useProgressCtx.hideCheckout();
}
function handleCloseConfirm() {
useProgressCtx.hideCheckout();
cartCtx.clearCart();
clearData();
}
function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
const customerData = Object.fromEntries(formData.entries());
sendRequest(
JSON.stringify({
order: {
items: cartCtx.items,
customer: customerData,
},
})
);
}
let actions = (
<>
<Button textOnly type="button" onClick={handleCloseCheckout}>
Cancel
</Button>
<Button>Confirm</Button>
</>
);
if (isSending) {
actions = <span>Your Order is sending...</span>;
}
if (data && !error) {
return (
<Modal open={useProgressCtx.progress === "checkout"} onClose={handleCloseConfirm}>
<div>
<h2>Order completed</h2>
<p>your order has complated, we will send bill via Email.</p>
</div>
<p className="modal-actions">
<Button textOnly type="button" onClick={handleCloseConfirm}>
Confirm
</Button>
</p>
</Modal>
);
}
return (
<>
<Modal open={useProgressCtx.progress === "checkout"} onClose={handleCloseCheckout}>
<form onSubmit={handleSubmit}>
<h2>Checkout</h2>
<p>Total Amount: {currencyFormatter.format(cartTotal)} </p>
<Input label="Full Name" type="text" id="name" />
<Input label="E-Mail Adress" type="email" id="email" />
<Input label="Street" type="text" id="street" />
<div className="control-row">
<Input label="City" type="text" id="city" />
<Input label="Postal Code" type="text" id="postal-code" />
</div>
{error && <Error title="An error occurred!" message={error} />}
<p className="modal-actions">{actions}</p>
</form>
</Modal>
</>
);
}