javaScript/react

라우터

부엉이사장 2024. 7. 30. 08:33

# react 라우터 설치

npm install react-router-dom@6

 

 

index.js에서

import { BrowserRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
    <App />
    </BrowserRouter>
  </React.StrictMode>
);

저렇게 추가해주자.

 

 

 

app.js에서

import { Routes, Route, Link } from 'react-router-dom';

이렇게 Route라이브러리 임포트 해주고

      <Routes>
        <Route path="/detail" element={<div>detail</div>} />
        <Route path="/cart" element={<div>cart</div>} />
      </Routes>

이렇게 Route태그에다가 path와 element를 넣어주면 element에 있는 태그가 해당 경로에 생긴다.

저기 element는 무쪼건 태그하나로 시작해서 하나로 끝나야한다.

http://127.0.0.1:3000/detail

vue에서처럼 ground인 app.js에 있는 html이 뜨고

거기에 추가되는 컴포넌트같음.

이걸 요약할수 있는 기능이 있을거임. 컴포넌트로 할듯

 

function App() {
  const [shoes, setShoes] = useState(products);

  return (
    <div className="App">
      <Navbar bg="light" data-bs-theme="light">
        <Container>
          <Navbar.Brand href="#home">Muzzi</Navbar.Brand>
          <Nav className="me-auto">
            <Nav.Link href="/">Home</Nav.Link>
            <Nav.Link href="detail">Detail</Nav.Link>
            <Nav.Link href="cart">Cart</Nav.Link>
          </Nav>
        </Container>
      </Navbar>
      <Routes>
        <Route path="/detail" element={<div>detail</div>} />
        <Route path="/cart" element={<div>cart</div>} />

        <Route
          path="/"
          element={
            <div>
              <div
                className="main-bg"
                style={{ backgroundImage: `url('${bg}')` }}
              ></div>

              <div className="img-box">
                {shoes.map((data, index) => {
                  return <Product key={index} data={data}></Product>;
                })}
              </div>
            </div>
          }
        />
      </Routes>
    </div>
  );
}

이렇게 Route에 경로도 설정해주니까 뭐 적용 잘된다.

참고로 만든 html태그를 home에 넣어줬음.

 

 

 

# Link

      {/* 링크 */}
      <Link to="/">home</Link>
      <Link to="/detail">상세</Link>

저렇게 Link쓸수 있음

주석은 저렇게 쓴다. 

 

 

# 컴포넌트 나누기

const 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>
  );
};

export default Detail;

Detail.js라는 파일에 컴포넌트 코드를 넣어줌. 

그리고 export Detail로 설정.

//App.js에서
import Detail from './Detail.js';

App.js에서 해당 컴포넌트를 import한 후,

        <Route path="/detail" element={<Detail />} />

이렇게 태그 갖다 넣어주면 됨.

난 참고로 Detail.js에서 return을 안해서 안됐었음.

상품별로 링크로 들어가는건 파라미터를 배워야할듯.

 

#파라미터 안쓰고 대충 만들어보기

일단 Detail component에다가 파라미터 만들어줌

const Detail = ({ index, data }) => {
  return (
    <div className="container">
      <div className="row">
        <div className="col-md-6">
          <img src={data[index].src} width="100%" />
        </div>
        <div className="col-md-6">
          <h4 className="pt-5">{data[index].title}</h4>
          <p>{data[index].content}</p>
          <p>{data[index].price}</p>
          <button className="btn btn-danger">주문하기</button>
        </div>
      </div>
    </div>
  );
};

export default Detail;

그리고 app.js에서

//bootstrap
import Button from 'react-bootstrap/Button';
import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import Card from 'react-bootstrap/Card';

//data
import bg from './img/bg.png';
import products from './products.js';

//native react
import { useState } from 'react';
import './App.css';

//library
import { Routes, Route, Link, useNavigate } from 'react-router-dom';

//component
import Detail from './Detail.js';

function App() {
  const navigate = useNavigate();
  const [shoes, setShoes] = useState(products);

  const [mode, setMode] = useState({
    nowIndex: 0,
  });

  const changeIndex = (i) => {
    console.log('muzzi babo');
    const copy = { ...mode };
    copy.nowIndex = i;
    setMode(copy);
    navigate('/detail');
  };

  return (
    <div className="App">
      <Navbar bg="light" data-bs-theme="light">
        <Container>
          <Navbar.Brand href="/">Muzzi</Navbar.Brand>
          <Nav className="me-auto">
            <Nav.Link href="/">Home</Nav.Link>
            <Nav.Link href="detail">Detail</Nav.Link>
            <Nav.Link href="cart">Cart</Nav.Link>
          </Nav>
        </Container>
      </Navbar>

      {/* 링크 */}
      <Link to="/">home</Link>
      <Link to="/detail">상세</Link>

      <Routes>
        <Route
          path="/"
          element={
            <div>
              <div
                className="main-bg"
                style={{ backgroundImage: `url('${bg}')` }}
              ></div>

              <div className="img-box">
                {shoes.map((data, index) => {
                  return (
                    <Product
                      key={index}
                      data={data}
                      onClick={() => {
                        changeIndex(index);
                      }}
                    ></Product>
                  );
                })}
              </div>
            </div>
          }
        />

        <Route
          path="/detail"
          element={<Detail index={mode.nowIndex} data={shoes} />}
        />
        <Route path="/cart" element={<div>cart</div>} />
      </Routes>
    </div>
  );
}

const Product = ({ data, onClick }) => {
  return (
    <Card
      className="babo"
      style={{ width: '18rem' }}
      key={data.id}
      onClick={onClick}
    >
      <Card.Img variant="top" src={`${data.src}`} />
      <Card.Body>
        <Card.Title>{data.title}</Card.Title>
        <Card.Text>{data.content}</Card.Text>
        <Card.Text>{data.price}</Card.Text>
        <Button variant="primary">Buy</Button>
      </Card.Body>
    </Card>
  );
};

export default App;

useNavigate써주고 인수 넘겨줬음

map에 돌린 Product태그에 onclick이 안되서 

onClick통째로 넘겨주고 Product컴포넌트에서 Card에다가 onClick이벤트 달아줬음

 

 

# navigate사용

navigate('/detail')

 

 

이 함수가 라우터 바꿔주는거. 당연 뒤로가기앞으로가기 편해짐

navigate(-1)

뒤로 이동

앞으로는 1넣어주면 되고..

 

        <Route
          path="/detail"
          element={
            <Detail index={mode.nowIndex} data={shoes} navigate={navigate} />
          }
        />

이렇게 Detail component에다가 navigate넣어주고

 

          <button
            className="btn btn-danger"
            onClick={() => {
              navigate(-1);
            }}
          >
            뒤로가기
          </button>

Detail component에 onClick버튼으로 뒤로가기 버튼 만들어줌.

동작함

 

 

# 404페이지 만들기

        <Route path="*" element={<div>404</div>}></Route>

모든 경로 *을 저 element보이게

 

 

 

 

# nested route

import { Routes, Route, Link, useNavigate, Outlet } from 'react-router-dom';

이렇게 Outlet을 임포트함

        <Route path="/about" element={<About></About>}>
          <Route path="location" element={<Location />}></Route>
          <Route path="history" element={<History />}></Route>
        </Route>

/about으로가면 About컴포넌트, 

/about/location으로 가면 Location컴포넌트

/about/history로 가면 History컴포넌트 보여주게함

 

const About = () => {
  return (
    <div>
      <h4>info</h4>
      <Outlet></Outlet>
    </div>
  );
};

const History = () => {
  return (
    <div>
      <h4>history</h4>
    </div>
  );
};

const Location = () => {
  return (
    <div>
      <h4>location</h4>
    </div>
  );
};

컴포넌트는 이렇게 만들어주고

About컴포넌트에 Outlet태그를 넣어줘야 /location이냐 /history냐에 따라서 보여주는 컴포넌트가 달라짐.

 

 

 

# 파라미터 사용하기

              <h1>아래건 파라미터로</h1>
              <div className="img-box">
                {shoes.map((data, index) => {
                  return (
                    <Product
                      key={index}
                      data={data}
                      onClick={() => {
                        changeParams(index);
                      }}
                    ></Product>
                  );
                })}
              </div>

메인페이지에서 파라미터로 가는 태그를 따로 만들어줬다.

아래껄 누르면 파라미터로 링크이동하게 해줄거다.

onClick에 파라미터 이동 함수를 달아줬는데, 

  const changeParams = (i) => {
    navigate(`/detail/${i}`);
  };

걍 대충 navigate함수로 썼음

 

그럼 Detail.js에서

import { useParams } from 'react-router-dom';

const Detail = ({ index, data, navigate, onClick }) => {
  let { id } = useParams();
  if (id) {
    index = id;
  }

  return (
    <div className="container">
      <div className="row">
        <div className="col-md-6">
          <img src={data[index].src} width="100%" />
        </div>
        <div className="col-md-6">
          <h4 className="pt-5">{data[index].title}</h4>
          <p>{data[index].content}</p>
          <p>{data[index].price}</p>
          <button
            className="btn btn-danger"
            onClick={() => {
              navigate(-1);
            }}
          >
            뒤로가기
          </button>
        </div>
      </div>
    </div>
  );
};

export default Detail;

useParams를 사용한다고 임포트해주고

만약 파라미터가 달려있으면 index를 파라미터로 해주고, 

없으면 그냥 인수로 받은 index를 쓰라고했다.

 

그럼 동작한다.

http://127.0.0.1:3000/detail/gadgf 

이렇게 파라미터 ㅄ같으면 에러띄워주더라.

404를 안띄워줌. 뭐 고치려면 고칠수있을텐데 귀찮음..

if문 쓰면될듯.

 

 

# 파라미터 확장

/detail/:id/dsdsd/:number이런식으로 하면됨.

 

 

 

# 숙제

//bootstrap
import Button from 'react-bootstrap/Button';
import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import Card from 'react-bootstrap/Card';

//data
import bg from './img/bg.png';
import products from './products.js';

//native react
import { useState } from 'react';
import './App.css';

//library
import { Routes, Route, Link, useNavigate, Outlet } from 'react-router-dom';

//component
import Detail from './Detail.js';

function App() {
  const navigate = useNavigate();
  const [shoes, setShoes] = useState(products);

  const [mode, setMode] = useState({
    nowIndex: 0,
  });

  const changeIndex = (i) => {
    const copy = { ...mode };
    copy.nowIndex = i;
    setMode(copy);
    navigate('/detail');
  };

  const changeParams = (i) => {
    navigate(`/detail/${i}`);
  };

  const arrange = () => {
    const copy = [...shoes];
    const sortedProducts = copy.slice().sort((a, b) => {
      if (a.title < b.title) return -1;
      if (a.title > b.title) return 1;
      return 0;
    });
    setShoes(sortedProducts);
  };

  return (
    <div className="App">
      <Navbar bg="light" data-bs-theme="light">
        <Container>
          <Navbar.Brand href="/">Muzzi</Navbar.Brand>
          <Nav className="me-auto">
            <Nav.Link href="/">Home</Nav.Link>
            <Nav.Link href="detail">Detail</Nav.Link>
            <Nav.Link href="cart">Cart</Nav.Link>
          </Nav>
        </Container>
        <button className="btn btn-primary" onClick={arrange}>
          Sort
        </button>
      </Navbar>

      {/* 링크 */}
      <Link to="/">home</Link>
      <Link to="/detail">상세</Link>

      <Routes>
        <Route
          path="/"
          element={
            <div>
              <div
                className="main-bg"
                style={{ backgroundImage: `url('${bg}')` }}
              ></div>

              <div className="img-box">
                {shoes.map((data, index) => {
                  return (
                    <Product
                      key={index}
                      data={data}
                      onClick={() => {
                        changeIndex(index);
                      }}
                    ></Product>
                  );
                })}
              </div>
              <h1>아래건 파라미터로</h1>
              <div className="img-box">
                {shoes.map((data, index) => {
                  return (
                    <Product
                      key={index}
                      data={data}
                      onClick={() => {
                        changeParams(index);
                      }}
                    ></Product>
                  );
                })}
              </div>
            </div>
          }
        />

        <Route
          path="/detail"
          element={
            <Detail index={mode.nowIndex} data={shoes} navigate={navigate} />
          }
        />
        <Route path="/cart" element={<div>cart</div>} />
        <Route path="*" element={<div>404</div>}></Route>

        <Route
          path="/detail/:id"
          element={
            <Detail index={mode.nowIndex} data={shoes} navigate={navigate} />
          }
        />
        <Route path="/cart" element={<div>cart</div>} />
        <Route path="*" element={<div>404</div>}></Route>

        <Route path="/about" element={<About></About>}>
          <Route path="location" element={<Location />}></Route>
          <Route path="history" element={<History />}></Route>
        </Route>

        <Route path="/event" element={<Event />}>
          <Route path="one" element={<One />}></Route>
          <Route path="two" element={<Two />}></Route>
        </Route>
      </Routes>
    </div>
  );
}

const Product = ({ data, onClick }) => {
  return (
    <Card
      className="babo"
      style={{ width: '18rem' }}
      key={data.id}
      onClick={onClick}
    >
      <Card.Img variant="top" src={`${data.src}`} />
      <Card.Body>
        <Card.Title>{data.title}</Card.Title>
        <Card.Text>{data.content}</Card.Text>
        <Card.Text>{data.price}</Card.Text>
        <Button variant="primary">Buy</Button>
      </Card.Body>
    </Card>
  );
};

const About = () => {
  return (
    <div>
      <h4>info</h4>
      <Outlet></Outlet>
    </div>
  );
};

const History = () => {
  return (
    <div>
      <h4>history</h4>
    </div>
  );
};

const Location = () => {
  return (
    <div>
      <h4>location</h4>
    </div>
  );
};

const Event = () => {
  return (
    <div>
      <h4>오늘의 이벤트</h4>
      <Outlet></Outlet>
    </div>
  );
};

const One = () => {
  return (
    <div>
      <p>첫 주문시 양배추즙 서비스</p>
      <Outlet></Outlet>
    </div>
  );
};

const Two = () => {
  return (
    <div>
      <p>생일기념 쿠폰받기</p>
      <Outlet></Outlet>
    </div>
  );
};
export default App;