React Styled-component 

* Styled-component를 사용하면 css파일이 없어도 된다

Styled-component 설치 : npm install styled-components

import styled from 'styled-components'

 

사용법 : let 변수명 = styled.button `내용` = 버튼을 만든것이고, 백틱으로 내용 설정

끌어와서 쓰려면 <변수명 />으로 사용

 

장점 : 다른 js파일에 관섭을 하지 않는다. 페이지 로딩 시간 단축

 

해당하는것도 props를 이용해서 특정 부분만 변경 가능

 

단점 : js파일이 복잡해짐. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React Lifecycle & useEffect

Lifecycle : 컴포넌트의 주기(장착, 업데이트, 삭제 시 실행 가능)

쓰는 방법 : useEffect(() => { 실행할 내용 }) 

* 페이지가 모두 렌더링 된 후 useEffect()안에 내용이 실행된다

쓰는 이유 : 연산이 오래 걸리는 경우, 같이 쓰게 될 경우, 페이지 로딩이 느려질 수도 있다

* 보통 시간이 오래걸리는 어려운 작업, 서버에서 데이터를 가져오는 작업 등을 useEffect()안에 사용

 

useEffect(() => { 실행할 내용 }, [변수]) : 변수가 변할때만 실행 하도록 설정  

변수 없이 []만 쓸 경우, mount될때는 실행되지만, update가 될때는 실행안된다

 

* useEffect안에 return () => {실행할 내용} : 해당 내용은 useEffect가 실행되기 전에 실행

return을 쓰는 이유 : react는 재렌더링이 많기 때문에, 재렌더링 되었을때 기존의 것을 제거 등을 할 때 사용(충돌 방지)

* return은 mount될 때 실행 x, unmount 될 때 실행

 

setTimeout(함수, 시간) : 해당 시간이 지난후, 함수 실행

clearTimeout(타이머 변수명) : 해당 타이머를 제거

 

총정리 

1. 재렌더링마다 코드 실행 하고 싶으면 : useEffect(() => {코드})

2. mount시 1회 코드 실행 하고 싶으면 : useEffect(() => {코드}, [])

3. unmount시 1회 코드 실행 or useEffect 실행 전 코드 실행 하고 싶으면 : useEffect(() => { return () => {코드} })

4. 특정 state 변경시에만 실행 하고 싶으면 : useEffect(() => {코드}, [변수])  

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

function Detail(props){
  let {id} = useParams();
  let 찾은상품 = props.shoes.find(function(x){
    return x.id == id
  });
  let [count, setCount] = useState(0);
  //let [alert, setAlert] = useState(true)
  let [num, setNum] = useState('');

  useEffect(()=>{
    if (isNaN(num) == true){
      alert('그러지마세요')
    }
  }, [num])

  // useEffect(() => {
  //   let a = setTimeout(() => {setAlert(false)}, 2000)
  //   console.log(2)
  //   return () => {
  //     console.log(1)
  //     clearTimeout(a);
  //   }
  // }, [])

  return(
    <div className="container">
      {
        alert == true 
        ? <div className="alert alert-warning">
          2초 이내 구매시 할인
          </div>
        : null
      }
      
      {count}
      <button onClick={() => {setCount(count+1)}}>버튼</button>
      <div className="row">
        <div className="col-md-6">
          <img src="https://codingapple1.github.io/shop/shoes1.jpg" width="100%" />
        </div>
        <div className="col-md-6">
          
          <input onChange={(e) => {setNum(e.target.value)}} />
          
          <h4 className="pt-5">{찾은상품.title}</h4>
          <p>{찾은상품.content}</p>
          <p>{찾은상품.price}원</p>

          <button className="btn btn-danger">주문하기</button> 
        </div>
      </div>
    </div> 
  )
}

export default Detail;

 

실행 결과 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React ajax

ajax로 GET/POST요청하려면 방법 3가지 = XMLHttpRequest, fetch(), axios

axios 라이브러리 설치 : npm install axios - import axios from 'axios'

axios.get('url') : url에 해당하는 데이터 불러옴

.then() : 해당하는 데이터 가져옴

.catch() : 가져오는데 실패하였을 때 

 

* 여러개의 url에게 get요청을 보내고 싶을 때 : Promise.all([axios.get('url'), axios.get('url') , ...]).then()

* fetch()를 쓰게되면, json형식을 변환하는 과정이 필요하지만, axios는 자동으로 해준다

import { Container, Nav, Navbar } from 'react-bootstrap';
import './App.css';
import bg from './img/bg2.jpg';
import { useState } from 'react';
import data from './data.js';
import { Routes, Route, Link, useNavigate, Outlet} from 'react-router-dom'
import Detail from './routes/Detail.js'
import axios from 'axios'

function App() {

  let [shoes, setShoes] = useState(data)

  let navigate = useNavigate();

  return (
    <div className="App">
      
      <Navbar bg="light" data-bs-theme="light">
        <Container>
          <Navbar.Brand href="#home">ShopShop</Navbar.Brand>
          <Nav className="me-auto">
            <Nav.Link onClick={() => { navigate('/')}}>Home</Nav.Link>
            <Nav.Link onClick={() => { navigate('/detail') }}>Detail</Nav.Link>
          </Nav>
        </Container>
      </Navbar>

      <Routes>
        <Route path='/' element={
          <>
          <div className='main-bg' style={{backgroundImage:'url(' + bg + ')' }}></div>
            <div className='container'>
              <div className='row'>
                {
                  shoes.map(function(a, i){
                    return(
                      <Card shoes = {shoes[i]} i = {i}></Card>
                    )
                  })
                }
              </div>
            </div>
            <button onClick={() => {
              axios.get('https://codingapple1.github.io/shop/data2.json')
              .then((data) => {
                console.log(data.data);
                let copy = [...shoes, ...data.data];
                setShoes(copy)
              })
              .catch(() => {
                console.log('실패함')
              })

            }}>더보기</button>
          </>
        } />
        <Route path='/detail/:id' element={<Detail shoes={shoes}/>} />
      </Routes>
      
    </div>
  );
}

function Card(props){
  return(
    <div className='col-md-4'>
      <img src={"https://codingapple1.github.io/shop/shoes" + (props.i+1) + ".jpg"} width="80%"></img>
      <h5>{props.shoes.title}</h5>
      <p>{props.shoes.price}</p>
    </div>
  )
}

export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React 탭 UI 

* if문을 쓰고 싶다면, 컴포넌트 사용

import React, { useEffect, useState } from "react";
import { Nav } from "react-bootstrap";
import { useParams } from "react-router-dom";

function Detail(props){
  let {id} = useParams();
  let 찾은상품 = props.shoes.find(function(x){
    return x.id == id
  });

  let [alert, setAlert] = useState(true)
  let [탭, 탭변경] = useState(0);

  useEffect(() => {
    let a = setTimeout(() => {setAlert(false)}, 2000)
    console.log(2)
    return () => {
      console.log(1)
      clearTimeout(a);
    }
  }, [])

  return(
    <div className="container">
      {
        alert == true 
        ? <div className="alert alert-warning">
          2초 이내 구매시 할인
          </div>
        : null
      }
  
      <div className="row">
        <div className="col-md-6">
          <img src="https://codingapple1.github.io/shop/shoes1.jpg" width="100%" />
        </div>
        <div className="col-md-6">
          
          <h4 className="pt-5">{찾은상품.title}</h4>
          <p>{찾은상품.content}</p>
          <p>{찾은상품.price}원</p>

          <button className="btn btn-danger">주문하기</button> 
        </div>
      </div>

      <Nav variant="tabs" defaultActiveKey="link0">
        <Nav.Item>
          <Nav.Link onClick={() => {탭변경(0)}} eventKey="link0">버튼0</Nav.Link>
        </Nav.Item>
        <Nav.Item>
          <Nav.Link onClick={() => {탭변경(1)}} eventKey="link1">버튼1</Nav.Link>
        </Nav.Item>
        <Nav.Item>
          <Nav.Link onClick={() => {탭변경(2)}} eventKey="link2">버튼2</Nav.Link>
        </Nav.Item>
      </Nav>
      <TabContent 탭={탭}></TabContent>

    </div> 
  )
}

function TabContent(props){
  // if (props.탭 == 0) {
  //   return <div>내용0</div>
  // } else if (props.탭 == 1) {
  //   return <div>내용1</div>
  // } else if (props.탭 == 2) {
  //   return <div>내용2</div>
  // }
  return [<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][props.탭]
}

export default Detail;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React transition (전환 애니메이션)

전환 애니메이션 만드는법 

1. 애니메이션 동작 전 className 만들기

2. 애니메이션 동작 후 className 만들기

3. className에 transition 속성 추가

4. 원할 때 2번 className 부착

* className은 여러개 넣고 싶을 때는 띄어쓰기로 구분한다

* automatic batching기능때문에, 효과를 주려면, setTimout() 사용

import React, { useEffect, useState } from "react";
import { Nav } from "react-bootstrap";
import { useParams } from "react-router-dom";

function Detail(props){
  let {id} = useParams();
  let 찾은상품 = props.shoes.find(function(x){
    return x.id == id
  });

  let [alert, setAlert] = useState(true)
  let [탭, 탭변경] = useState(0);
  let [fade2, setFade2] = useState('')

  useEffect(() => {
    let a = setTimeout(() => {setAlert(false)}, 2000)
    console.log(2)
    return () => {
      console.log(1)
      clearTimeout(a);
    }
  }, [])

  useEffect(() => {
    setFade2('end')
    return () => {
      setFade2('')
    }
  })

  return(
    <div className={"containe start " + fade2}>
      
      {
        alert == true 
        ? <div className="alert alert-warning">
          2초 이내 구매시 할인
          </div>
        : null
      }
  
      <div className="row">
        <div className="col-md-6">
          <img src="https://codingapple1.github.io/shop/shoes1.jpg" width="100%" />
        </div>
        <div className="col-md-6">
          
          <h4 className="pt-5">{찾은상품.title}</h4>
          <p>{찾은상품.content}</p>
          <p>{찾은상품.price}원</p>

          <button className="btn btn-danger">주문하기</button> 
        </div>
      </div>

      <Nav variant="tabs" defaultActiveKey="link0">
        <Nav.Item>
          <Nav.Link onClick={() => {탭변경(0)}} eventKey="link0">버튼0</Nav.Link>
        </Nav.Item>
        <Nav.Item>
          <Nav.Link onClick={() => {탭변경(1)}} eventKey="link1">버튼1</Nav.Link>
        </Nav.Item>
        <Nav.Item>
          <Nav.Link onClick={() => {탭변경(2)}} eventKey="link2">버튼2</Nav.Link>
        </Nav.Item>
      </Nav>
      <TabContent 탭={탭}></TabContent>

    </div> 
  )
}

function TabContent(props){

  let [fade, setFade] = useState('')

  useEffect(() => {
    let a = setTimeout(() =>{setFade('end')}, 100)
    return () => {
      clearTimeout(a)
      setFade('')
    }
  }, [props.탭])

  return (<div className={"start " + fade }>
      {[<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][props.탭]}
    </div>)
}

export default Detail;

 

실행 결과

 

 

 

 

 

 

 

 

React Bootstrap 설치

Bootstrap 라이브러리 설치 : react bootstrap 검색 (https://react-bootstrap.netlify.app/) - Get Started - npm ~~ 복사

- terminal창 붙여넣기 

 

CSS 부분 복사 - App.js 상단에 붙여넣기

 

또는 

이 부분 복사 - public/index.html - head태그 안쪽에 붙여넣기

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React Bootstrap 사용

https://react-bootstrap.netlify.app/ - GetStarted - (ctrl + k)로 검색창 열기 - 검색

필요한 것(button) 검색 - 복사 - App.js 붙여넣기 

 

* 가져온 컴포넌트는 import 해줘야 한다

* import 부분은 from 'react-bootstrap' 이다.

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React 이미지 및 public폴더 이용

이미지 넣는법1 : css파일 - background-image: url('이미지 경로');

이미지 넣는법2 : App.js파일 - import 작명 from '경로'; - backgroundImage: 'url(' + 이미지 경로 + ')';

 

* <img src="경로"> 할 때, 다른 웹사이트에서도 가져와도 된다.

* 하지만, 저장한 사진을 가져올 때는, import를 해야하지만 public 폴더 안에 있는 사진을 가져올 때에는

* (./이미지 이름) 으로만 가져올 수 있다. 

대신 process.env.PUBLIC_URL + '경로' 로 작성해야 효과적이다

 

import { Container, Nav, Navbar } from 'react-bootstrap';
import './App.css';
import bg from './img/bg2.jpg';

function App() {
  return (
    <div className="App">
      <Navbar bg="light" data-bs-theme="light">
        <Container>
          <Navbar.Brand href="#home">ShopShop</Navbar.Brand>
          <Nav className="me-auto">
            <Nav.Link href="#home">Home</Nav.Link>
            <Nav.Link href="#features">Cart</Nav.Link>
          </Nav>
        </Container>
      </Navbar>

      <div className='main-bg' style={{backgroundImage:'url(' + bg + ')' }}></div>

      <div className='container'>
        <div className='row'>
          <div className='col-md-4'>
            <img src='https://codingapple1.github.io/shop/shoes1.jpg' width="80%"></img>
            <h4>상품명</h4>
            <p>상품설명</p>
          </div>
          <div className='col-md-4'>
            <img src='https://codingapple1.github.io/shop/shoes2.jpg' width="80%"></img>
            <h4>상품명</h4>
            <p>상품설명</p>
          </div>
          <div className='col-md-4'>
          <img src='https://codingapple1.github.io/shop/shoes3.jpg' width="80%"></img>
            <h4>상품명</h4>
            <p>상품설명</p>
          </div>
        </div>
      </div>
    </div>
  );
}

export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React import & export 

export 

보낼 변수가 하나일 경우 = export default 변수명 

보낼 변수가 여러개일 경우 = export {변수명, 변수명, ...}

import

받을 변수가 하나일 경우 = import 변수명 from '경로'

받을 변수가 여러개일 경우 = import {변수명, 변수명, ...} from '경로'

 

* 함수도 export, import 가능

import { Container, Nav, Navbar } from 'react-bootstrap';
import './App.css';
import bg from './img/bg2.jpg';
import { useState } from 'react';
import data from './data.js';

function App() {

  let [shoes] = useState(data)
  let [img] = useState(['https://codingapple1.github.io/shop/shoes1.jpg', 'https://codingapple1.github.io/shop/shoes2.jpg', 'https://codingapple1.github.io/shop/shoes3.jpg'])

  return (
    <div className="App">
      
      <Navbar bg="light" data-bs-theme="light">
        <Container>
          <Navbar.Brand href="#home">ShopShop</Navbar.Brand>
          <Nav className="me-auto">
            <Nav.Link href="#home">Home</Nav.Link>
            <Nav.Link href="#features">Cart</Nav.Link>
          </Nav>
        </Container>
      </Navbar>

      <div className='main-bg' style={{backgroundImage:'url(' + bg + ')' }}></div>

      <div className='container'>
        <div className='row'>
          {
            shoes.map(function(a, i){
              return(
                <Shoes shoes={shoes} num={i} img={img}></Shoes>
              )
            })
          }
        </div>
      </div>
    </div>
  );
}

function Shoes(props){
  return(
    <div className='col-md-4'>
      <img src={props.img[props.num]} width="80%"></img>
      <h4>{props.shoes[props.num].title}</h4>
      <p>{props.shoes[props.num].price}</p>
    </div>
  )
}

export default App;
let data = [
    {   
    id : 0,
    title : "White and Black",
    content : "Born in France",
    price : 120000
    },
    {
    id : 1,
    title : "Red Knit",
    content : "Born in Seoul",
    price : 110000
    },
    {
    id : 2,
    title : "Grey Yordan",
    content : "Born in the States",
    price : 130000
    }
]

export default data;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React 라우터 셋팅 및 기본

페이지 나누는 법 

1. 컴포넌트 만들어서 상세페이지내용 채움

2. 누가 /detail 접속하면 그 컴포너트를 보여줌

 

react-router-dom 라이브러리 사용

라이브러리 설치 : npm install react-router-dom@6

index.js - <BrowserRouter>태그 안에 <App> 넣기

* BrowerRouter도 import를 해준다

 

App.js - import { Routes, Route, Link} from 'react-router-dom' 입력

 

* 페이지 이동 버튼 : <Link>태그 사용, to로 경로 지정

import { Container, Nav, Navbar } from 'react-bootstrap';
import './App.css';
import bg from './img/bg2.jpg';
import { useState } from 'react';
import data from './data.js';
import { Routes, Route, Link} from 'react-router-dom'
//import Detail from './test.js'

function App() {

  let [shoes] = useState(data)
  let [img] = useState(['https://codingapple1.github.io/shop/shoes1.jpg', 'https://codingapple1.github.io/shop/shoes2.jpg', 'https://codingapple1.github.io/shop/shoes3.jpg'])

  return (
    <div className="App">
      
      <Navbar bg="light" data-bs-theme="light">
        <Container>
          <Navbar.Brand href="#home">ShopShop</Navbar.Brand>
          <Nav className="me-auto">
            <Nav.Link href="#home">Home</Nav.Link>
            <Nav.Link href="#features">Cart</Nav.Link>
          </Nav>
        </Container>
      </Navbar>

      <Link to="/">홈</Link>
      <Link to="/detail">상세페이지</Link>

      <Routes>
        <Route path='/' element={
          <>
          <div className='main-bg' style={{backgroundImage:'url(' + bg + ')' }}></div>
            <div className='container'>
              <div className='row'>
                {
                  shoes.map(function(a, i){
                    return(
                      <Shoes shoes={shoes} num={i} img={img}></Shoes>
                    )
                  })
                }
              </div>
            </div>
          </>
        } />
        <Route path='/detail' element={<Detail></Detail>} />
      </Routes>
      
    </div>
  );
}

function Detail(){
  return(
    <div className="container">
      <div className="row">
        <div className="col-md-6">
          <img src="https://codingapple1.github.io/shop/shoes1.jpg" width="100%" />
        </div>
        <div className="col-md-6">
          <h4 className="pt-5">상품명</h4>
          <p>상품설명</p>
          <p>120000원</p>
          <button className="btn btn-danger">주문하기</button> 
        </div>
      </div>
    </div> 
  )
}

function Shoes(props){
  return(
    <div className='col-md-4'>
      <img src={props.img[props.num]} width="80%"></img>
      <h4>{props.shoes[props.num].title}</h4>
      <p>{props.shoes[props.num].price}</p>
    </div>
  )
}

export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React 라우터 (navigate, nested routes, outlet)

App.js - import { Routes, Route, Link, useNavigate, Outlet} from 'react-router-dom' 입력

 

useNavigate() : 페이지 이동을 도와주는 역할

let navigate = useNavigate() 로 변수 지정 - navigate('경로') = 해당 경로로 이동

* 경로대신 -1을 적으면, 전페이지로 이동

 

404페이지 설정

: <Route path='*' element={<div>없는 페이지</div>} />

 

nested Routes : 경로 안에 경로를 설정할 때, route태그 안에 route태그를 넣어서 설정

 

* 하지만, 이상태로 실행하면 /about/member를 들어가도 /about내용만 보인다

(/about 안에 /about/member내용을 넣는 방식, 하지만 /about만 보인다)

따라서 <About>컴포넌트 내용에 <Outlet>을 입력한다.

그러면 <Outlet>을 입력한 곳에 /about/member 내용이 들어간다

 

nested routes 사용 시기 : 페이지는 이동되지만, 몇가지만 변할 때 사용

import { Container, Nav, Navbar } from 'react-bootstrap';
import './App.css';
import bg from './img/bg2.jpg';
import { useState } from 'react';
import data from './data.js';
import { Routes, Route, Link, useNavigate, Outlet} from 'react-router-dom'
import Detail from './routes/Detail.js'

function App() {

  let [shoes] = useState(data)
  let [img] = useState(['https://codingapple1.github.io/shop/shoes1.jpg', 'https://codingapple1.github.io/shop/shoes2.jpg', 'https://codingapple1.github.io/shop/shoes3.jpg'])

  let navigate = useNavigate();

  return (
    <div className="App">
      
      <Navbar bg="light" data-bs-theme="light">
        <Container>
          <Navbar.Brand href="#home">ShopShop</Navbar.Brand>
          <Nav className="me-auto">
            <Nav.Link onClick={() => { navigate('/')}}>Home</Nav.Link>
            <Nav.Link onClick={() => { navigate('/detail') }}>Detail</Nav.Link>
          </Nav>
        </Container>
      </Navbar>

      <Routes>
        <Route path='/' element={
          <>
          <div className='main-bg' style={{backgroundImage:'url(' + bg + ')' }}></div>
            <div className='container'>
              <div className='row'>
                {
                  shoes.map(function(a, i){
                    return(
                      <Shoes shoes={shoes} num={i} img={img}></Shoes>
                    )
                  })
                }
              </div>
            </div>
          </>
        } />
        <Route path='/detail' element={<Detail />} />

        <Route path='/about' element={<About />}>
          <Route path='member' element={<div>멤버임</div>} />
          <Route path='location' element={<div>위치정보임</div>} />
        </Route>
        <Route path='/event' element={<Event />}>
          <Route path='one' element={<div>첫 주문시 양배추즙 서비스</div>} />
          <Route path='two' element={<div>생일 기념 쿠폰 받기</div>} />
        </Route>
      </Routes>
      
    </div>
  );
}

function Event(){
  return(

    <div>
      <h3>오늘의 이벤트</h3>
      <Outlet></Outlet>
    </div>
    
  )
}

function About(){
  return(
    <div>
      <h4>회사정보임</h4>
      <Outlet></Outlet>
    </div>
  )
}

function Shoes(props){
  return(
    <div className='col-md-4'>
      <img src={props.img[props.num]} width="80%"></img>
      <h4>{props.shoes[props.num].title}</h4>
      <p>{props.shoes[props.num].price}</p>
    </div>
  )
}

export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React 라우터 (URL 파라미터)

* 경로 뒤에 :변수명 = URL 파라미터

받은 파라미터값은 useParams()로 받는다 (import 해야한다)

사용할 때는 {}를 벗기고 사용

 

* find() : array 자료안에서 원하는 항목만 찾아올 수 있습니다. 

array자료.find(()=>{ return 조건식 })  이렇게 쓰면 조건식에 맞는 자료를 찾아서 이 자리에 남겨줍니다.

 

import { Container, Nav, Navbar } from 'react-bootstrap';
import './App.css';
import bg from './img/bg2.jpg';
import { useState } from 'react';
import data from './data.js';
import { Routes, Route, Link, useNavigate, Outlet} from 'react-router-dom'
import Detail from './routes/Detail.js'

function App() {

  let [shoes] = useState(data)
  let [img] = useState(['https://codingapple1.github.io/shop/shoes1.jpg', 'https://codingapple1.github.io/shop/shoes2.jpg', 'https://codingapple1.github.io/shop/shoes3.jpg'])

  let navigate = useNavigate();

  return (
    <div className="App">
      
      <Navbar bg="light" data-bs-theme="light">
        <Container>
          <Navbar.Brand href="#home">ShopShop</Navbar.Brand>
          <Nav className="me-auto">
            <Nav.Link onClick={() => { navigate('/')}}>Home</Nav.Link>
            <Nav.Link onClick={() => { navigate('/detail') }}>Detail</Nav.Link>
          </Nav>
        </Container>
      </Navbar>

      <Routes>
        <Route path='/' element={
          <>
          <div className='main-bg' style={{backgroundImage:'url(' + bg + ')' }}></div>
            <div className='container'>
              <div className='row'>
                {
                  shoes.map(function(a, i){
                    return(
                      <Shoes shoes={shoes} num={i} img={img}></Shoes>
                    )
                  })
                }
              </div>
            </div>
          </>
        } />
        <Route path='/detail/:id' element={<Detail shoes={shoes}/>} />


      </Routes>
      
    </div>
  );
}

function Shoes(props){
  return(
    <div className='col-md-4'>
      <img src={props.img[props.num]} width="80%"></img>
      <h4>{props.shoes[props.num].title}</h4>
      <p>{props.shoes[props.num].price}</p>
    </div>
  )
}

export default App;
import { useParams } from "react-router-dom";

function Detail(props ){

    let {id} = useParams();
    let 찾은상품 = props.shoes.find(function(x){
      return x.id == id
    });

    return(
      <div className="container">
        <div className="row">
          <div className="col-md-6">
            <img src="https://codingapple1.github.io/shop/shoes1.jpg" width="100%" />
          </div>
          <div className="col-md-6">

            
            <h4 className="pt-5">{찾은상품.title}</h4>
            <p>{찾은상품.content}</p>
            <p>{찾은상품.price}원</p>

            <button className="btn btn-danger">주문하기</button> 
          </div>
        </div>
      </div> 
    )
  }

export default Detail;

 

실행 결과

 

 

 

 

 

 

 

 

React input

종류 : text, range, checkbox 등등

e.target.value : 입력한 값을 가져옴

e.stopPropagation() : 상위 html로 퍼지는 이벤트버블링을 막고 싶을때 사용

splice() : 배열에서 특정 인덱스 삭제

/* eslint-disable */
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';

function App() {

  let [글제목, 글제목변경] =useState(['남자 코트 추천', '강남 우동맛집', '파이썬독학'])
  let [따봉, 따봉변경] = useState([0, 0, 0]);
  let [modal, setModal] = useState(false);
  let [title, setTitle] = useState(1);
  let [입력값, 입력값변경] = useState('');

  return (
    <div className="App">
      <div className="black-nav">
        <h4>ReactBlog</h4>
      </div>
      <span>{입력값}</span>
      {
        글제목.map(function(a, i){
          return (
            <div className='list'>
              <h4 onClick={() => {setModal(!modal); setTitle(i) }}>{a}, {i} 
              <span onClick={ (e) => {
                  e.stopPropagation();
                  let copy = [...따봉];
                  copy[i] = copy[i] + 1;
                  따봉변경(copy)} }>👍
                </span> {따봉[i]}
                <button onClick={(e) => {
                  e.stopPropagation(); 
                  let copy = [...글제목];
                  copy.splice(i, 1);
                  글제목변경(copy);
                }}>
                삭제</button>
              </h4>
              <p>217일 발행</p>
            </div>
          )
        })
      }

      <input onChange={(e) => { 입력값변경(e.target.value); console.log(입력값) }}></input>
      <button>버튼</button>

      {
        modal == true 
        ? <Modal title= {title} func={() => {let copy = [...글제목]; copy[0] = '여자 코트 추천'; 글제목변경(copy)}} color={'skyblue'} 글제목={글제목}/> 
        : null
      }

    </div>
  );
}

function Modal(props){
  return(
    <div className='modal' style={{background : props.color}}>
      <h4>{props.글제목[props.title]}</h4>
      <p>날짜</p>
      <p>상세내용</p>
      <button onClick={props.func}>글수정</button>
    </div>
  )
}
export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React class (중요 x)

function 대신 class 이용

 

 

 

 

 

 

 

 

 

React 컴포넌트

 

컴포넌트 만드는법 : function을 만듦 - return() 안에 html 담기 - <함수명></함수명>으로 사용

* 함수명은 첫글자 대문자

* 의미없는 <div>대신 <></> 사용 가능

 

* 어떤걸 컴포넌트로 만들면 좋은지 : 반복적인 것, 큰 페이지들, 자주 변경되는 것

* 컴포넌트 단점 : state를 가져다쓸 때 문제가 생긴다

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React 동적 UI

만드는 방법 : 미리 디자인 완성 - 현재 상태를 state로 저장 - state에따라 어떻게 보일지 작성

* if문 대신 삼항연산자 사용(? : )

/* eslint-disable */
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';

function App() {

  let [글제목, 글제목변경] =useState(['남자 코트 추천', '강남 우동맛집', '파이썬독학'])
  let [따봉, 따봉변경] = useState(0);
  let [modal, setModal] = useState(false);

  return (
    <div className="App">
      <div className="black-nav">
        <h4>ReactBlog</h4>
      </div>

      <button onClick={ () => { 
        let copy = [...글제목];
        copy[0] = '여자 코트 추천'
        글제목변경(copy) 
      }}>글 수정</button>

      <div className='list'>
        <h4>{글제목[0]} <span onClick={ () => {따봉변경(따봉+1)} }>👍</span> {따봉} </h4>
        <p>217일 발행</p>
      </div>
      <div className='list'>
        <h4>{글제목[1]}</h4>
        <p>217일 발행</p>
      </div>
      <div className='list'>
        <h4 onClick={() => {setModal(!modal)}}>{글제목[2]}</h4>
        <p>217일 발행</p>
      </div>

      {
        modal == true ? <Modal/> : null
      }

    </div>
  );
}

function Modal(){
  return(
    <div className='modal'>
      <h4>제목</h4>
      <p>날짜</p>
      <p>상세내용</p>
    </div>
  )
}

export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React 반복문 (map)

array자료형.map(function(a, i){}) : map 자료형

1. array 자료 갯수만큼 함수안의 코드 실행

2. 함수의 파라미터는 array안에 있던 자료 

3. return에 뭐 적으면 array로 담아줌

* a = array자료형의 내용, i = index번호

 

주의 : state내용을 변경하려면, copy로 복사 후, [...변수명]로 화살표(경로) 재지정

/* eslint-disable */
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';

function App() {

  let [글제목, 글제목변경] =useState(['남자 코트 추천', '강남 우동맛집', '파이썬독학'])
  let [따봉, 따봉변경] = useState([0, 0, 0]);
  let [modal, setModal] = useState(false);

  return (
    <div className="App">
      <div className="black-nav">
        <h4>ReactBlog</h4>
      </div>

      {/* <div className='list'>
        <h4>{글제목[0]} <span onClick={ () => {따봉변경(따봉+1)} }>👍</span> {따봉} </h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4>{글제목[1]}</h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4 onClick={() => {setModal(!modal)}}>{글제목[2]}</h4>
        <p>2월 17일 발행</p>
      </div> */}

      {
        글제목.map(function(a, i){
          return (
            <div className='list'>
              <h4>{a}, {i} <span onClick={ () => {
                  let copy = [...따봉];
                  copy[i] = copy[i] + 1;
                  따봉변경(copy)} }>👍
                </span> {따봉[i]}
              </h4>
              <p>217일 발행</p>
            </div>
          )
        })
      }

    </div>
  );
}

export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React props (state 자식과 부모)

부모가 자식에게만 state 전달 가능(props문법 이용) (자식에서 부모는 전송 불가) 

1. <자식컴포넌트 작명={state이름}>

2. props 파라미터 등록 후, props.작명 이용

* props == 파라미터 문법 (일반 문자도 전송 가능)

/* eslint-disable */
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';

function App() {

  let [글제목, 글제목변경] =useState(['남자 코트 추천', '강남 우동맛집', '파이썬독학'])
  let [따봉, 따봉변경] = useState([0, 0, 0]);
  let [modal, setModal] = useState(false);

  return (
    <div className="App">
      <div className="black-nav">
        <h4>ReactBlog</h4>
      </div>

      {/* <div className='list'>
        <h4>{글제목[0]} <span onClick={ () => {따봉변경(따봉+1)} }>👍</span> {따봉} </h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4>{글제목[1]}</h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4 onClick={() => {setModal(!modal)}}>{글제목[2]}</h4>
        <p>2월 17일 발행</p>
      </div> */}

      {
        글제목.map(function(a, i){
          return (
            <div className='list'>
              <h4 onClick={() => {setModal(!modal)}}>{a}, {i} <span onClick={ () => {
                  let copy = [...따봉];
                  copy[i] = copy[i] + 1;
                  따봉변경(copy)} }>👍
                </span> {따봉[i]}
              </h4>
              <p>217일 발행</p>
            </div>
          )
        })
      }
      {
        modal == true ? 
          <Modal func={() => {let copy = [...글제목]; copy[0] = '여자 코트 추천'; 글제목변경(copy)}} color={'skyblue'} 글제목={글제목}/> : null
      }

    </div>
  );
}

function Modal(props){
  return(
    <div className='modal' style={{background : props.color}}>
      <h4>{props.글제목[0]}</h4>
      <p>날짜</p>
      <p>상세내용</p>
      <button onClick={props.func}>글수정</button>
    </div>
  )
}
export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React props 활용

/* eslint-disable */
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';

function App() {

  let [글제목, 글제목변경] =useState(['남자 코트 추천', '강남 우동맛집', '파이썬독학'])
  let [따봉, 따봉변경] = useState([0, 0, 0]);
  let [modal, setModal] = useState(false);
  let [title, setTitle] = useState(1);

  return (
    <div className="App">
      <div className="black-nav">
        <h4>ReactBlog</h4>
      </div>

      {/* <div className='list'>
        <h4>{글제목[0]} <span onClick={ () => {따봉변경(따봉+1)} }>👍</span> {따봉} </h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4>{글제목[1]}</h4>
        <p>2월 17일 발행</p>
      </div>
      <div className='list'>
        <h4 onClick={() => {setModal(!modal)}}>{글제목[2]}</h4>
        <p>2월 17일 발행</p>
      </div> */}

      {
        글제목.map(function(a, i){
          return (
            <div className='list'>
              <h4 onClick={() => {setModal(!modal); setTitle(i) }}>{a}, {i} <span onClick={ () => {
                  let copy = [...따봉];
                  copy[i] = copy[i] + 1;
                  따봉변경(copy)} }>👍
                </span> {따봉[i]}
              </h4>
              <p>217일 발행</p>
            </div>
          )
        })
      }
      {
        modal == true ? 
          <Modal title= {title} func={() => {let copy = [...글제목]; copy[0] = '여자 코트 추천'; 글제목변경(copy)}} color={'skyblue'} 글제목={글제목}/> : null
      }

    </div>
  );
}

function Modal(props){
  return(
    <div className='modal' style={{background : props.color}}>
      <h4>{props.글제목[props.title]}</h4>
      <p>날짜</p>
      <p>상세내용</p>
      <button onClick={props.func}>글수정</button>
    </div>
  )
}
export default App;

 

실행 결과

 

 

 

 

 

 

 

 

 

React 개발환경 세팅

nodejs 검색 - 왼쪽 설치 

vscode 검색 - 설치 

작업할 폴더 생성 - shift 우클릭 - powershell창 열기 

- npx create-react-app 프로젝트명 

* 오류발생시 : 윈도우 검색 - powershell - 우클릭 - 관리자 권한으로 실행 - Set-ExecutionPolicy Unrestricted 입력

vscode - 해당 폴더 열기 

node_modules : 라이브러리 모아놓은 곳

public : static 파일 모아놓은 곳(img)

src : 소스코드 보관함

package.json : 프로젝트 정보

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React 실행 

실행 : terminal - new terminal - npm start 

* App.js : 메인 페이지

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React 레이아웃 (JSX 문법)

* html 내용은 return () 안에다가 짜야한다

JSX : js파일에서 쓰는 html 대용품

* App.js에서 App.css파일을 가져오려면 className을 설정한 후, 해당 내용을 App.css파일에 작성

import './App.css' 도 해줘야 한다

 

 

중괄호 문법 : 변수명을 중괄호 안에 입력하면, 알아서 값을 가져온다 (거의 모든곳에서 사용 가능)

해당하는 역할을 data binding이라 한다

 

 

 

css를 css파일에서 불러올 수 있지만, 직접 부여할 수도 있다.

style = {{이름 : '값'}} 형식으로 넣어줘야 한다 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React state 

* return ()안에는 하나의 영역(<div>)만 있어야 한다

state : 중요한 자료를 저장하는 변수 문법 (자료를 잠깐 보관)

* let이나 var로 변수를 저장하면 되는데, state를 쓰는 이유는 변수 내용이 변경되었을 때

state는 자동으로 html에 반연되어 재랜더링 해준다

사용법 : let [작명(a), 작명(b)] = useState('내용') : useState는 import 해야한다

{a} : 해당 내용을 불러옴

b : state 변경을 도와주는 함수

 

* Destructuring 문법 : let [a, c] = [1, 2]  //a = 1, b = 2

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React state (버튼 및 개수 추가 기능)

* /* eslint-disable */ : 노란색 warning 메시지를 끄는 기능(Lint 끄는 기능)

* onclick 안에는 함수만 가능

* state 변경하는법 : state변경함수(새로운 state)

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

React state (array 변경)

* array 데이터는 내용을 저장하지 않고, 경로만 저장

따라서 해당내용을 만드려면 경로(화살표)를 바꿔줘야 한다 

[...변수명] : 해당 변수를 화살표를 벗기고 다시 씌운다.

 

실행 결과

 

 

 

 

 

 

SPRING 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ H2 데이터베이스 설치

https://www.h2database.com/html/main.html - All Platforms 다운 - 압축 풀기 - 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING web socket

 web socket : 양방향 통신 (채팅)

https://mvnrepository.com/ - spring websocket 검색 - 첫번째 클릭 

- 아무버전 클릭 - maven 내용 복사 - pom.xml(${org.springframework-version}) 붙여넣기

 

https://mvnrepository.com/ - jackson databind 검색 - 첫번째 클릭 

- 2.12.1 버전 클릭 - maven 내용 복사 - pom.xml 붙여넣기

 

 

socket 관련 class 생성(TestSocket.java)

 

기본 설정 : servlet-context.xml - Namespaces - websocket 체크

 servlet-context.xml - Source -  

<beans:bean id="ts" class="socket 관련 class(TestSocket) 경로" /> : 빈 생성

<websocket:handlers>

<websocket:mapping handler="ts" path="/chat" /> : /chat 을 요청하면 ts객체를 바로보게끔 설정

<websocket:sockjs /> : socket api를 사용할 수 있게 설정

</websocket:handlers>

 

* TestSocket.java - extends TextWebSocketHandler

 

TestSocket.java - Override/Implement Methods - AbstractWebSocketHandler

- after~closed, after~Established, handleTextMessage 체크 - ok

afterConnectionEstablished : 클라이언트가 연동되면 실행

handleTextMessage : 사용자가 메시지를 보내면 실행

afterConnectionClosed : 클라이언트가 종료 및 연결이 끊기면 실행

 

 

해당 test_socket.jsp 페이지에 접속시, 지정한 세션을 부여한다.

"상담사 연결" 버튼을 누르면, chat()함수로 이동한 후, socket이라는 경로의 페이지로 이동한다.

 

 

* controller에서 부여한 session과 TestSocket.java에서 받은 session은 타입이 다르다.

따라서, servlet-context.xml - Source - 

<websocket:handshake-interceptors>
<beans:bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor" />
</websocket:handshake-interceptors>

을 추가한다.

 

 

session.getId() : WebSocketSession에서 부여한 session

session.getAttributes() : controller에서 부여한 session

List에는 session 전체를 넣고, Map에는 key에 session.getId(), value에는 session.getAttributes().get("name")

 

 

TextMessage message로 넘어온 값을 message.getPayload() = 입력한 내용 받아오기

sessionMap.get(session.getId()) : Map에 session.getId()를 통해 밸류가 얻어오기(ex. 홍길동1)

sessionList의 forEach문을 통해, .sendMessage(text)를 통해 문자 전달하기

 

 

연결이 끊겼을 때, 알려주는 역할

 

 

let sock = null : WebSocket 객체를 저장한 변수 sock 선언

let wsUri : "ws://localhost:8080/root/chat/websocket" : 연결이 설정될 WebSocket URI 지정

sock = new WebSocket(wsUri) : 지정된 uri로 새 WebSocket연결을 생성

sock.onmessage = onMessage : 들어오는 메시지를 처리하는 함수 onMessage를 설정

sock.onclose = onClose : 연결이 닫힐 때 처리하는 함수 onClose를 설정

$("#send_msg").keydown( (key) => {
if (key.keyCode == 13) {} }) : 엔터키를 눌렀을때 함수 실행

sock.send() : 추출한 메시지를 서버로 전송

.append() : 요소 끝에 계속 추가하는 역할

 

실행 결과

 

+ Recent posts