리액트로 웹사이트 만들기

LeeKyungwon·2024년 4월 16일
0

프론트엔드 

목록 보기
26/56
post-custom-banner

React Router

리액트에서 컴포넌트로 페이지를 나누도록 해주는 라이브러리

리액트 라우터의 핵심 컴포넌트에는
Router, Routes, Route, Link 이렇게 4가지가 있다.

Router

리액트 라우터에서 사용하는 데이터들을 모두 갖고 있다.(현재 주소, 페이지 기록)
라우터 컴포넌트도 내부적으로는 Context Provider이다.
라우터에서 제공하는 기능을 사용하려면 반드시 라우터 컴포넌트 안에서 사용해야 한다.

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

function Main() {
  return <BrowserRouter> ... </BrowserRouter>;
}

export default Main;

Routes, Route

주로 같이 사용된다.
자바스크립트의 switch문 같은 것
차례대로 경로를 살펴보다가 맞는 경로를 찾으면 그 안에 있는 컴포넌트를 보여준다.

<Routes>
  <Route path="/" element = {<HomePage/>}/>
  <Route path="courses" element = {<CourseListPage/>}/>
  <Route path="courses/1" element = {<CoursePage/>}/>
  <Route path="*" element = {<NotFoundPage/>}/>
Router

element 프롭은 컴포넌트 함수가 아니라 jsx를 넘겨준다.

a태그 대신 사용된다.

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

<Link to="/">홈페이지<Link>
<Link to="/course">수업 탐색<Link>
<Link to="/questions">커뮤니티<Link>

<Link to={`/courses/${course.slug}`}>{course.title}</Link>

-> 목데이터의 각 데이터를 구분하는 문자열로 접근, 여기서는 slug가 고유한 문자열임

리액트 라우터 설치하기

npm install react-router-dom@6
-> react-router 패키지 버전 6으로 설치한다는 의미

주의할 점!

react-router-dom 패키지에서 임포트해야한다.
(react-router 라는 패키지는 리액트 라우터를 만드는 개발자들이 내부적으로 사용하는 것이기 때문)

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

메뉴에서 사용하는 링크, style이라는 프롭으로 함수를 지정해줄 수 있다.

function getLinkStyle({ isActive }) {
  return {
    textDecoration: isActive ? 'underline' : '',
  };
}
 ...
 <NavLink style={getLinkStyle} to="/courses">
              카탈로그
 </NavLink>

하위 페이지 나누기

리액트 라우터에서는 라우트를 중첩해서 사용할 수 있다.

<Route path="courses">
            <Route index element={<CourseListPage />} />
            <Route path="react-frontend-development" element={<CoursePage />} />
</Route>

라우트가 많아졌을 때 경로나 용도에 따라서 분리할 수 있고 path도 훨씬 간단해진다.
원래 path 였던 곳은 index로

공통 레이아웃을 보여주고 싶을때는 엘리먼트를 지정하고 지정한 컴포넌트 안에서는 Outlet을 사용한다.
Routes 안에서는 Route만 사용하기 때문에 엘리먼트로 사용한다.

Main.js

function Main() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<App />}>
          <Route index element={<HomePage />} />
          <Route path="courses">
            <Route index element={<CourseListPage />} />
            <Route path="react-frontend-development" element={<CoursePage />} />
          </Route>
          <Route path="questions" element={<QuestionListPage />} />
          <Route path="questions/616825" element={<QuestionPage />} />
          <Route path="wishlist" element={<WishlistPage />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

export default Main;

App.js

import { Outlet } from 'react-router-dom';
import Nav from '../components/Nav';
import Footer from '../components/Footer';
import styles from './App.module.css';
import './App.font.css';

function App() {
  return (
    <>
      <Nav className={styles.nav} />
      <div className={styles.body}><Outlet /></div>
      <Footer className={styles.footer} />
    </>
  );
}

export default App;

useParams

동적인 경로로 이동하는 것
콜론(:)으로 시작하는 문자열을 사용하면 경로에 파라미터를 지정할 수 있다.
(질문 리스트에서 질문 클릭하면 각 질문 페이지로 이동하는 경우)
Main.js

...
<Route path="courses">
            <Route index element={<CourseListPage />} />
            <Route path=":courseSlug" element={<CoursePage />} />
</Route>

CoursePage.js

import { useParams } from 'react-router-dom';
...
function CoursePage() {
  const { courseSlug } = useParams();
  const course = getCourseBySlug(courseSlug);
  const courseColor = getCourseColor(course?.code);

  const headerStyle = {
    borderTopColor: courseColor,
  };

  const handleAddWishlistClick = () => {
    addWishlist(course?.slug);
  };

  return (
    <>
      <div className={styles.header} style={headerStyle}>
        <Container className={styles.content}>
          <CourseIcon photoUrl={course.photoUrl} />
          <h1 className={styles.title}>{course.title}</h1>
          <Button variant="round" onClick={handleAddWishlistClick}>
            + 코스 담기
          </Button>
          <p className={styles.summary}>{course.summary}</p>
        </Container>
      </div>
      <Container className={styles.topics}>
        {course.topics.map(({ topic }) => (
          <Card className={styles.topic} key={topic.slug}>
            <h3 className={styles.title}>{topic.title}</h3>
            <p className={styles.summary}>{topic.summary}</p>
          </Card>
        ))}
      </Container>
    </>
  );
}

export default CoursePage;

없는 페이지 처리하기

Routes 맨 마지막에 Route 추가해주고 path="*"로 설정해주면 된다.

페이지에 접속했는데 어떤 이유 때문에 다른 페이지로 이동시키는 것

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

...

  if (!course) {
    return <Navigate to="/courses" />;
  }

useSearchParams로 쿼리 사용하기

검색창에서
CourseListPage.js

import { useSearchParams } from 'react-router-dom';
...

function CourseListPage() {
  const [searchParam, setSearchParam] = useSearchParams();
  const initKeyword = searchParam.get('keyword');
  const [keyword, setKeyword] = useState(initKeyword || '');
  const courses = getCourses(initKeyword);

  const handleKeywordChange = (e) => setKeyword(e.target.value);

  const handleSubmit = (e) => {
    e.preventDefault();
    setSearchParam(keyword ? { keyword } : {});
  };

  return (
    <ListPage
      variant="catalog"
      title="모든 코스"
      description="자체 제작된 코스들로 기초를 쌓으세요."
    >
      <form className={searchBarStyles.form} onSubmit={handleSubmit}>
        <input
          name="keyword"
          value={keyword}
          onChange={handleKeywordChange}
          placeholder="검색으로 코스 찾기"
        ></input>
        <button type="submit">
          <img src={searchIcon} alt="검색" />
        </button>
      </form>

      <p className={styles.count}>{courses.length}개 코스</p>

      {initKeyword && courses.length === 0 ? (
        <Warn
          className={styles.emptyList}
          title="조건에 맞는 코스가 없어요."
          description="올바른 검색어가 맞는지 다시 한 번 확인해 주세요."
        />
      ) : (
        <div className={styles.courseList}>
          {courses.map((course) => (
            <CourseItem key={course.id} course={course} />
          ))}
        </div>
      )}
    </ListPage>
  );
}

export default CourseListPage;

useNavigate

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

...
  const handleAddWishlistClick = () => {
    addWishlist(course?.slug);
    navigate('/wishlist');
  };

react-helmet

react-helmet이라는 라이브러리로 페이지 제목을 바꿀 수 있다.
사용 방법은 Helmet이라는 컴포넌트로 감싼 다음에, 안에 <title> 태그로 덮어쓰면 된다.

import { Helmet } from 'react-helmet';
import Button from '../components/Button';
import Container from '../components/Container';
import Lined from '../components/Lined';
import styles from './HomePage.module.css';
import landingImg from '../assets/landing.svg';

function HomePage() {
  return (
    <>
      <Helmet>
        <title>Codethat - 코딩이 처음이라면, 코드댓</title>
      </Helmet>
      <div className={styles.bg} />
      <Container className={styles.container}>
        <div className={styles.texts}>
          <h1 className={styles.heading}>
            <Lined>코딩이 처음이라면,</Lined>
            <br />
            <strong>코드댓</strong>
          </h1>
          <p className={styles.description}>
            11만 명이 넘는 비전공자, 코딩 입문자가 코드댓 무제한 멤버십을
            선택했어요.
            <br />
            지금 함께 시작해보실래요?
          </p>
          <div>
            <Button>지금 시작하기</Button>
          </div>
        </div>
        <div className={styles.figure}>
          <img src={landingImg} alt="그래프, 모니터, 윈도우, 자물쇠, 키보드" />
        </div>
      </Container>
    </>
  );
}

export default HomePage;

클라이언트 사이드 렌더링 (CSR)

웹 브라우저에서 자바스크립트로 HTML 페이지를 만드는 것

싱글 페이지 애플리케이션 (SPA)

하나의 HTML 문서 안에서 자바스크립트로 여러 페이지를 보여주는 사이트

post-custom-banner

0개의 댓글