$ npm i react-router-dom
main.jsx에서 라우터 적용한다.
BrowserRouter가 감싸고 있어야 라우팅을 사용 할 수 있다.
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import { BrowserRouter } from "react-router-dom";
ReactDOM.createRoot(document.getElementById("root")).render(
<BrowserRouter>
<App />
</BrowserRouter>
);
만들어놓은 모든 페이지를 라우팅한다.
import React from "react";
import { Route, Routes } from "react-router-dom";
import HomePage from "../Home/HomePage";
import ProductsPage from "../Products/ProductsPage";
import SingleProductPage from "../SingleProduct/SingleProductPage";
import SignupPage from "../Authentication/SignupPage";
import LoginPage from "../Authentication/LoginPage";
import CartPage from "../Cart/CartPage";
import MyOrderPage from "../MyOrderPage/MyOrderPage";
const Routing = () => {
return (
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/products" element={<ProductsPage />} />
<Route path="/product/:id" element={<SingleProductPage />} />
<Route path="/signup" element={<SignupPage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/cart" element={<CartPage />} />
<Route path="/myorders" element={<MyOrderPage />} />
</Routes>
);
};
export default Routing;
App.jsx에서 routing 컴포넌트를 적용한다.
import "./App.css";
import Navbar from "./components/Navbar/Navbar";
import Routing from "./components/Routing/Routing";
function App() {
return (
<div className="app">
<Navbar />
<main>
<Routing />
</main>
</div>
);
}
export default App;
navbar에서 link 알맞게 수정한다.
<div className="align_center navbar_links">
<LinkWithIcon title="홈페이지" link="." emoji={rocket} />
<LinkWithIcon title="상품들" link="/products" emoji={star} />
<LinkWithIcon title="로그인" link="/login" emoji={idButton} />
<LinkWithIcon title="가입" link="/signup" emoji={memo} />
<LinkWithIcon title="내주문" link="/myorders" emoji={order} />
<LinkWithIcon title="로그아웃" link="." emoji={lock} />
<a href="/cart" className="align_center">
장바구니 <p className="align_center cart_counts">0</p>
</a>
</div>
잘 적용됐는지 확인해본다.
그리고
라우터 사용 시에는 a태그를 잘 사용하지 않기 때문에 Navlink로 수정한다.
import { NavLink } from "react-router-dom";
import "./LinkWithIcon.css";
const LinkWithIcon = ({ title, link, emoji }) => {
return (
<NavLink to={link} className="align_center">
{title} <img src={emoji} alt="" className="link_emoji" />
</NavLink>
);
};
export default LinkWithIcon;
<NavLink to="/cart" className="align_center">
장바구니 <p className="align_center cart_counts">0</p>
</NavLink>
href -> to
/* 네브 링크로 클릭 시 active 들어감 */
.navbar_links > a.active {
font-weight: 600;
}
active 시 링크가 굵게 표시된다.
axios설치 후 백엔드 데이터 가져오기
utils폴더 생성 후
axios를 사용하기 위한 js파일을 만든다.
import axios from "axios";
//axios에 미리 백엔드 앞부분 주소를 저장한다.
export default axios.create({
baseURL: "http://localhost:5000/api",
});
요청을 할 때 api 뒷부분 부터 요청하면됨
default로 설정 시 가져올 때 이름을 마음대로 설정이 가능함
ProductsList.jsx
import apiClient from "../../utils/api-client";
const ProductsList = () => {
const [products, setProducts] = useState([]); // 상품들
const [error, setError] = useState(""); //에러
//처음 실행 시 apiClient에 products에서 가져온다
useEffect(() => {
apiClient
.get("/products") //base주소 뒤에 붙여짐
.then((res) => setProducts(res.data.products)) //성공 시 res 나오면 products에 res의 data를 저장함
.catch((err) => setError(err)); //에러 발생 시 에러에 저장한다.
}, []);
저장 후 확인한다.
<section className="products_list_section">
<header className="align_center products_list_header">
<h2>상품목록</h2>
<select name="sort" id="" className="products_sorting">
<option value="">정렬방법</option>
<option value="price desc">가격높은순</option>
<option value="price asc">가격낮은순</option>
<option value="rate desc">평점높은순</option>
<option value="rate asc">평점낮은순</option>
</select>
</header>
<div className="products_list">
{/* 에러가 있을 경우 에러 표시 */}
{error && <em className="form_error">{error}</em>}
{/* products가 있을 경우 반복문으로 출력 */}
{products.map((product) => (
<ProductCard key={product._id} />
))}
</div>
db의 개수만큼 출력되는게 확인이되면
ProductCard에 props로 데이터를 전달해서 정보를 출력하도록 한다.
ProductsList.jsx
<div className="products_list">
{/* 에러가 있을 경우 에러 표시 */}
{error && <em className="form_error">{error}</em>}
{/* products가 있을 경우 반복문으로 출력 */}
{products.map((product) => (
<ProductCard
key={product._id}
id={product._id}
title={product.title}
image={product.images[0]}
price={product.price}
rating={product.reviews.rate}
ratingCounts={product.reviews.counts}
stock={product.stock}
/>
))}
</div>
</div>
import "./ProductCard.css";
import star from "../../assets/white-star.png";
import basket from "../../assets/basket.png";
import { Link, NavLink } from "react-router-dom";
const ProductCard = ({
id,
image,
price,
title,
rating,
ratingCounts,
stock,
}) => {
return (
<article className="product_card">
<div className="product_image">
<Link href={`product/${id}`}>
<img
src={`http://localhost:5000/products/${image}`}
// {image}만 넣으면 제대로 불러오지 못함
// 백엔드 서버 주소로 요청하면 됨
alt="product image"
/>
</Link>
</div>
<div className="product_details">
<h3 className="product_price">{price?.toLocaleString("ko-KR")} 원</h3>
{/* ?를 넣으면 데이터가 없더라도 에러가 나지않음 */}
<p className="product_title">{title}</p>
<footer className="align_center product_info_footer">
<div className="align_center">
<p className="align_center product_rating">
<img src={star} alt="star" /> {rating}
</p>
<p className="product_review_count">{ratingCounts}</p>
</div>
{/* 재고가 있을 경우에만 장바구니 담기 표시 */}
{stock > 0 && (
<button className="add_to_cart">
<img src={basket} alt="basket button" />
</button>
)}
</footer>
</div>
</article>
);
};
export default ProductCard;
이미지의 경우 이런식으로 직접 서버 주소로 요청해야 출력된다.
ProductsSidebar.jsx에도 위와 동일하게 카테고리를 백엔드에서 가져온다.
import "./ProductsSidebar.css";
import LinkWithIcon from "../Navbar/LinkWithIcon";
import apiClient from "../../utils/api-client";
import { useEffect, useState } from "react";
const ProductsSidebar = () => {
const [categories, setCategories] = useState([]);
const [error, setError] = useState("");
// 처음 실행 시 백엔드에서 데이터 가져오기
useEffect(() => {
apiClient
.get("/category") //category 에서
.then((res) => setCategories(res.data)) // 데이터가 있으면 저장
.catch((err) => setError(err.message)); // 에러가 있으면 저장
}, []);
return (
<aside className="products_sidebar">
<h2>카테고리</h2>
<div className="category_links">
{error && <em className="form_error">{error}</em>}
{categories.map((category) => (
<LinkWithIcon
key={category._id}
title={category.name}
link={`products?category=${category.name}`}
emoji={`http://localhost:5000/category/${category.image}`}
sidebar={true}
/>
))}
</div>
</aside>
);
};
export default ProductsSidebar;
'FRONTEND > React' 카테고리의 다른 글
[myCart] 리액트 로딩 스켈레톤 적용 (0) | 2023.12.20 |
---|---|
[myCart] 커스텀 Hook 생성 후 적용 (0) | 2023.12.20 |
[myCart] 몽고DB /백엔드 실행 (0) | 2023.12.20 |
[myCart] 회원가입 페이지 // 프로필 설정 (0) | 2023.12.19 |
[myCart] 로그인 페이지 /useRef()사용하여 비밀번호 숨김/보임 버튼 추가 /react-hook-form 라이브러리 사용 /유효성 검사 (0) | 2023.12.19 |