๊ด€๋ฆฌ ๋ฉ”๋‰ด

JiYoung Dev ๐Ÿ–ฅ

[React] Spring Boot์™€ ์—ฐ๋™ํ•˜์—ฌ shop ๋งŒ๋“ค๊ธฐ (2023.06.09) ๋ณธ๋ฌธ

full stack/React

[React] Spring Boot์™€ ์—ฐ๋™ํ•˜์—ฌ shop ๋งŒ๋“ค๊ธฐ (2023.06.09)

Shinjio 2023. 6. 9. 17:47

 

Spring Boot์™€ ์—ฐ๋™ํ•˜์—ฌ shop ๋งŒ๋“ค๊ธฐ

 

[Spring Boot] Spring Boot ์‚ฌ์šฉํ•˜๊ธฐ (2023.06.07)

Spring Boot ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์ค€๋น„ ๐ŸŽˆ ํ”„๋กœ๊ทธ๋žจ ์„ค์น˜ (Spring & MySQL) spring tool suite 4 Spring | Tools spring.io C๋“œ๋ผ์ด๋ธŒ ๋ฐ”๋กœ ์•„๋ž˜์— ์„ค์น˜ (ํ•„์ˆ˜๋Š” ์•„๋‹˜!) jarํŒŒ์ผ๋„ ์••์ถ•ํŒŒ์ผ์ด๋ผ ์••์ถ•ํ’€๊ธฐํ•˜๋ฉด ๋จ ๊ทธ๋Ÿฐ๋ฐ ์•ˆ๋˜๋Š” ๊ฒฝ

danyoujeong.tistory.com

 

 

CORS ์˜ค๋ฅ˜ (Cross Origin Resource Sysytem)
๊ต์ฐจ ์ถœ์ฒ˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ 

proxy ์„œ๋ฒ„(๋ฏธ๋“ค์›จ์–ด)๋กœ ํ•ด๊ฒฐ์„ ํ•˜์ž

setupProxy.js ๊ฒ€์ƒ‰

ํ”„๋ก์‹œ ์„œ๋ฒ„๋ž€ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ์‚ฌ์ด์—์„œ ๋ฐ์ดํ„ฐ ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ๋Œ€์‹  ๋ฐ›์•„์ฃผ๋Š” ์—ญํ• ์„ ํ•ด์คŒ
๋ณด์•ˆ์ƒ์˜ ๋ฌธ์ œ๋กœ ์ง์ ‘ ํ†ต์‹ ์„ ์ฃผ๊ณ  ๋ฐ›์„ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ํ”„๋ก์‹œ ์„œ๋ฒ„๊ฐ€ ์ค‘๊ณ„๋ฅผ ์ง„ํ–‰ํ•ด์คŒ

๋งŒ๋“ค๋•Œ src ํ•˜์œ„์— ํ•ด๋‹น ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์•ผ ํ•จ!

< ์ฐธ๊ณ ํ•  ๋ฌธ์„œ >
https://velog.io/@yunsungyang-omc/React-React-App%EC%97%90%EC%84%9C-CORS-%EC%9D%B4%EC%8A%88-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0

 

axios๋กœ spring boot ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ

 

  useEffect(() => {
    axios.get("http://172.30.1.42:8090/shop/").then((res) => {
      console.log("๊ฒฐ๊ณผ", res.data);
      setList(res.data);
    });
  }, []);

 

์ฃผ์†Œ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ local ํ˜ธ์ŠคํŠธ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Œ!

IP์ฃผ์†Œ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ

 

useSearchParams ์‚ฌ์šฉํ•˜์—ฌ ํ•„ํ„ฐ ๊ธฐ๋Šฅ ์ถ”๊ฐ€

 

ProductList.jsx

import React, { useState } from 'react'
import { useNavigate, useSearchParams } from 'react-router-dom';

const ProductList = ({list}) => {
    console.log('props', list);
    // type filter ์ž‘์—…์„ ๊ฑฐ์น˜๊ณ  ์‚ฌ์šฉํ•  list

    /**๋งŒ์•ฝ, '์›ํ”ผ์Šค' ํŽ˜์ด์ง€๋ฅผ ํด๋ฆญํ•˜๋ฉด type์ด dress์ธ๊ฒƒ๋งŒ
     * '์ „์ฒด' ํŽ˜์ด์ง€๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ „์ฒด ๋„์–ด์ฃผ๊ธฐ
     * useSearchParams ํ™œ์šฉ
     */

    const[typeParams, setTypeParams] = useSearchParams()
    let type = typeParams.get('type');

    //type filter ์ž‘์—…์„ ๊ฑฐ์น˜๊ณ  ์‚ฌ์šฉํ•  list
    let newList = type != null && list.filter(item => item.product.ptype == 'dress')

    const nav = useNavigate()

  return (
    <div>
        {/* Q.
        ์ƒํ’ˆ๋ช… - ๊ฐ€๊ฒฉ์„ 10๊ฐœ ์ƒํ’ˆ ๋ชจ๋‘ ๋„์›Œ์ค„ ๊ฒƒ
         */}

         {type == null 
            ? list.map((item)=>(
            <div key={item.product.pcode} onClick={()=>{nav(`/product/${item.product.pcode}`)}}>
            <img src={"data:image/;base64," + item.product.img} width='100px'></img>
            <p><strong>{item.product.pname}</strong> {item.product.price}</p>
            </div>
         )): newList.map((item)=>(
            <div key={item.product.pcode}>
            <img src={"data:image/;base64," + item.product.img} width='100px'></img>
            <p><strong>{item.product.pname}</strong> {item.product.price}</p>
            </div>
         ))}

    </div>
  )
}

export default ProductList

 

 

ํ•˜๋‚˜์˜ ์ƒํ’ˆ์— ๋Œ€ํ•œ ์ œํ’ˆ ์ •๋ณด spring boot์—์„œ ๊ฐ€์ ธ์˜ค๊ธฐ

useParam ์‚ฌ์šฉ

 

 

ํ˜„์žฌ ์Šคํ”„๋ง ๋ถ€ํŠธ๋ฅผ ํ†ตํ•ด /pcode ๊ฒฝ๋กœ ์ ‘์†ํ•˜๋ฉด pcode์— ํ•ด๋‹นํ•˜๋Š” ์ƒํ’ˆ 1๊ฐœ์˜ ์ •๋ณด๋งŒ ๋ณด์—ฌ์คŒ

 

ProductDetail.jsx

import React, { useEffect, useState } from 'react'
import { useParams } from 'react-router-dom'
import axios from "axios";

const ProductDetail = () => {

    let {num} = useParams()
    console.log('num', num);

    const [obj, setObj] = useState({});

    // axios๋ฅผ ํ†ตํ•ด์„œ ํ•œ๊ฐ€์ง€ ์ƒํ’ˆ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์˜ฌ ๊ฒƒ 
    useEffect(() => {
        axios.get(`http://172.30.1.42:8090/shop/${num}`)
        .then((res) => {
          console.log("detail ๊ฒฐ๊ณผ", res.data.product);
          setObj(res.data.product)
        });
      }, []);

    //   ์ง„์งœ ์•„์ดํ…œ์ด ์ž˜ ๋ณ€ํ–ˆ๋‚˜ ํ™•์ธํ•˜๊ณ  ์‹ถ์œผ๋ฉด ?
    //   useEffect(()=>{
    //     console.log(obj);
    //   }, [obj])

  return (
    <div>
        <div>
            <img src={"data:image/;base64," + obj.img} width='100px'></img>
            <p><strong>{obj.pname}</strong> {obj.price}</p>
        </div> 
    </div>
  )
}

export default ProductDetail

 

์ฃผ์˜์ 

UseEffect ์ฒ˜๋ฆฌ ์•ˆํ•ด์ฃผ๋ฉด?

๋ฌดํ•œ๋ฃจํ”„ ๋Œ๊ฑฐ๋‚˜ ๊ทธ ์ด์ „์— ์„ ํƒํ•œ ๊ฐ’์ด ๋‚˜ํƒ€๋‚จ(์‹œ์ ์ด ์•ˆ๋งž๋Š”๋‹ค)

 

App.js 

import { useEffect, useState } from "react";
import "./App.css";
import Header from "./components/Header";
import ProductDetail from "./components/ProductDetail";
import ProductList from "./components/ProductList";
import { Route, Routes } from "react-router-dom";
import axios from "axios";

function App() {
  const [list, setList] = useState([]);

  useEffect(() => {
    axios.get("http://172.30.1.42:8090/shop/").then((res) => {
      console.log("๊ฒฐ๊ณผ", res.data);
      setList(res.data);
    });
  }, []);

  return (
    <div className="App">
      <Header />
      <Routes>
        <Route path="/" element={<ProductList list={list} />}></Route>
        <Route path="/product/:num" element={<ProductDetail />}></Route>
      </Routes>
    </div>
  );
}

export default App;