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;

 

실행 결과

+ Recent posts