상품관리 - part4 상품 수정하기
ㆍProject Diary/React + Firebase (Snack ShoppingMall)
관리자가 기존에 등록된 상품 정보를 변경하는 방법 기록
1. 라우터 설정
먼저, 상품 수정 페이지로 이동할 수 있도록 라우터를 설정해야 합니다. react-router-dom을 사용하여 경로를 설정합니다.
import React from "react";
import { Route, Routes } from "react-router-dom";
import Layout from "@/Layout";
import ProductModifyView from "@/views/product/ProductModifyView";
const App = () => {
return (
<Routes>
<Route path="/" element={<Layout />}>
{/* 다른 경로 생략 */}
<Route path="/productModify" element={<ProductModifyView />} />
</Route>
</Routes>
);
};
export default App;
왜 라우터가 중요한가?
라우터는 사용자가 특정 경로로 이동할 때 해당 경로에 맞는 컴포넌트를 렌더링합니다.
상품 수정 페이지로 이동하기 위해서는 /productModify 경로를 설정하여 ProductModifyView 컴포넌트를 렌더링하도록 해야 합니다. 이를 통해 사용자가 상품 수정 페이지에 접근할 수 있습니다.
2. ProductModifyView 컴포넌트
ProductModifyView 컴포넌트는 상품 수정 페이지의 메인 컴포넌트입니다. 여기에서는 useLocation 훅을 사용하여 상품 정보를 전달받아 ProductModifySection 컴포넌트에 전달합니다.
import React from "react";
import ProductModifySection from "@/components/product/ProductModifySection";
import { useLocation } from "react-router-dom";
const ProductModifyView = () => {
const location = useLocation();
const { product } = location.state;
return (
<div>
<ProductModifySection item={product} />
</div>
);
};
export default ProductModifyView;
3. ProductModifySection 컴포넌트
ProductModifySection 컴포넌트는 실제 상품 정보를 수정하는 폼을 제공합니다.
import React, { useState } from "react";
import styled from "styled-components";
import { kuwazawa_productDB, oStorage } from "@/assets/firebase";
import { useNavigate } from "react-router-dom";
const ProductModifyBlock = styled.div`
//스타일 생략
`;
const OnlineShopModify = ({ item }) => {
const navigate = useNavigate();
const { category, name, price, description, inventory, photo, detailPhotos } = item;
const [product, setProduct] = useState({
category,
name,
price,
description,
inventory,
photo,
detailPhotos: [],
});
const [photoValue, setPhotoValue] = useState("");
const handleChange = (e) => {
const { value, name } = e.target;
setProduct((product) => ({ ...product, [name]: value }));
};
const handleFileChange = (e) => {
const file = e.target.files[0];
setProduct((prevProduct) => ({ ...prevProduct, photo: file }));
setPhotoValue(e.target.value);
};
const handleDetailFileChange = (e) => {
const files = e.target.files;
setProduct((prevProduct) => ({
...prevProduct,
detailPhotos: Array.from(files),
}));
};
const onSubmit = async (e) => {
e.preventDefault();
try {
const storageRef = oStorage.ref();
if (product.photo) {
const fileRef = storageRef.child(product.photo.name);
await fileRef.put(product.photo);
product.photo = await fileRef.getDownloadURL();
}
if (product.detailPhotos.length > 0) {
const detailPhotoURLs = [];
await Promise.all(
product.detailPhotos.map(async (file, index) => {
const fileName = `detailPhoto${index + 1}_${Date.now()}_${file.name}`;
const detailFileRef = storageRef.child(fileName);
await detailFileRef.put(file);
detailPhotoURLs.push(await detailFileRef.getDownloadURL());
})
);
product.detailPhotos = detailPhotoURLs;
}
await kuwazawa_productDB.child(item.key).update(product);
navigate("/product");
} catch (error) {
console.log("오류 : ", error);
}
};
return (
<ProductModifyBlock>
<h2>상품 수정</h2>
<form onSubmit={onSubmit}>
<div>
<label htmlFor="category">카테고리:</label>
//생략
</div>
<div>
<label htmlFor="name">상품명:</label>
//생략
</div>
<div>
<label htmlFor="price">가격:</label>
//생략
</div>
<div>
<label htmlFor="description">요약설명:</label>
//생략
</div>
<div>
<label htmlFor="inventory">재고:</label>
//생략
</div>
<div>
<label htmlFor="photo">상품사진:</label>
//생략
</div>
<div>
<label htmlFor="detailPhoto">상세 상품사진:</label>
//생략
</div>
<div className="btn">
<button type="submit">등록</button>
</div>
</form>
</ProductModifyBlock>
);
};
export default OnlineShopModify;
주요 코드를 설명하겠습니다
상태관리
const [product, setProduct] = useState({
category,
name,
price,
description,
inventory,
photo,
detailPhotos: [],
});
- 상태 관리는 useState 훅을 사용하여 상품 정보를 관리합니다.
- 초기 상태는 전달받은 item의 정보를 기반으로 설정됩니다.
입력 값 변경 핸들러
const handleChange = (e) => {
const { value, name } = e.target;
setProduct((product) => ({ ...product, [name]: value }));
};
입력 값이 변경될 때 상태를 업데이트하는 함수입니다.
setProduct((product) => ({ ...product, [name]: value }));
- 기존 product 객체를 스프레드 연산자(...product)를 사용하여 복사합니다
- [name]: value 부분은 객체의 속성 이름이 동적으로 설정되는 것을 의미합니다. name 변수의 값이 속성 이름이 되고, 해당 속성의 값은 value로 설정됩니다.
- 즉, product 객체의 특정 속성을 업데이트하거나 새로 추가하는 것입니다.
파일 입력 핸들러
const handleFileChange = (e) => {
const file = e.target.files[0];
setProduct((prevProduct) => ({ ...prevProduct, photo: file }));
setPhotoValue(e.target.value);
};
사진 파일이 변경될 때 상태를 업데이트하는 함수입니다.
setProduct((prevProduct) => ({ ...prevProduct, photo: file }));
- 기존 prevProduct 객체를 스프레드 연산자(...prevProduct)를 사용하여 복사합니다.
- photo: file 부분은 prevProduct 객체의 photo 속성을 file 값으로 설정합니다.
- 즉, prevProduct 객체의 photo 속성을 새로운 파일 값으로 업데이트합니다.
상세 사진 파일 입력 핸들러
const handleDetailFileChange = (e) => {
const files = e.target.files;
setProduct((prevProduct) => ({
...prevProduct,
detailPhotos: Array.from(files),
}));
};
여러 개의 상세 사진 파일을 처리하는 함수입니다.
setProduct((prevProduct) => ({ ...prevProduct, detailPhotos: Array.from(files) }));
- 기존 prevProduct 객체를 스프레드 연산자(...prevProduct)를 사용하여 복사합니다.
- detailPhotos: Array.from(files) 부분은 prevProduct 객체의 detailPhotos 속성을 files 배열의 복사본으로 설정합니다. Array.from(files)는 files를 새로운 배열로 변환합니다.
- prevProduct 객체의 detailPhotos 속성을 files 배열의 복사본으로 업데이트합니다.
폼 제출 핸들러
const onSubmit = async (e) => {
e.preventDefault();
try {
const storageRef = oStorage.ref();
if (product.photo) {
const fileRef = storageRef.child(product.photo.name);
await fileRef.put(product.photo);
product.photo = await fileRef.getDownloadURL();
}
if (product.detailPhotos.length > 0) {
const detailPhotoURLs = [];
await Promise.all(
product.detailPhotos.map(async (file, index) => {
const fileName = `detailPhoto${index + 1}_${Date.now()}_${file.name}`;
const detailFileRef = storageRef.child(fileName);
await detailFileRef.put(file);
detailPhotoURLs.push(await detailFileRef.getDownloadURL());
})
);
product.detailPhotos = detailPhotoURLs;
}
await kuwazawa_productDB.child(item.key).update(product);
navigate("/product");
} catch (error) {
console.log("오류 : ", error);
}
};
- 폼이 제출될 때 호출되는 함수입니다.
- Firebase Storage에 파일을 업로드하고 Realtime Database를 업데이트합니다.