제로초님의 "Next + React Query로 SNS 서비스 만들기" 클론 코딩중
# 0. 클론 코딩 할 사이트의 구조를 파악
트위터 사이트를 클론할 것이니 트위터의 구조를 살펴보자.
- 회원가입 팝업창, 로그인 팝업창 떴을 때 주소가 바뀐다.
- 로그인 팝업 띄우고 새로고침 -> 뒷 배경 보임
- 회원가입 팝업 띄우고 새로고침 -> 뒷 배경 안 보임
- Infinite Scrolling
- 왼쪽 메뉴(Navigation)
- 탭 전환
- 검색
- 로딩창
- 어떤 액션을 했을 때 주소가 바뀜 (Ex. 체크박스 on/off)
- 게시하기 버튼 클릭은 어느 화면에서 가능 (대신 이것도 버튼 누르면 주소 바뀜)
- 반응형 디자인
# 1. Next 프로젝트 생성
npx create-next-app@latest
근데 latest 버전으로 설치되니까 Next 15버전이 설치되었다..
별 생각없이 따라하다가 강의 화면과 다르게 나타나는 점이 있어 나중에 14버전으로 다시 설치했다.
# 2. Next 폴더 구조
public: next 서버에서 누구나 접근할 수 있게 serving 될 대상들
src: 개발 소스코드 폴더
ㄴ app: 라우팅 담당
app 폴더는 원래 src 바깥에 두는게 표준(?)인데
src 폴더를 가지게 되면 app 폴더에 포함되지 않는 이외의 소스코드를 app 폴더에 담지 않고 src 아래에 담을 수 있다. (취향차이)
next.config.js: next에 대한 설정
tsconfig.json: 타입스크립트 설정파일
# 3. path alias
@로 default 설정되어있음(@는 src를 가리킴)
'../../layout.tsx' -> @/app/layout.tsx 로 사용 가능
# 4. Next 프로젝트 실행
npm run dev
기본으로 3000 포트에서 돌아감
# 5. 폴더를 이용한 라우팅
기본 사용법
Next는 폴더 구조가 곧 URL 주소다.
app 폴더를 이용하면 라우팅을 쉽게 할 수 있다.
app 폴더 하위에 URL 체계 그대로 폴더를 생성해주면 된다.
http://localhost:3000/compose/tweet -> app/compose/tweet
http://localhost:3000/explore -> app/explore
동적 라우팅
근데 트위터에서
특정 사람의 게시글을 들어가면 {username}/status/{게시글ID} 이런 형태의 주소 체계를 가진다.
Next에서는 동적 라우팅 기능을 제공하며 대괄호를 이용하여 폴더를 생성하면 된다.
이 구조로 http://localhost:3000/elonmusk/status/121321321 로 접근하면?
-> elonmusk 유저의 게시글 ID가 121321321인 게시글 페이지가 된다.
# 6. 페이지
그리고 실제 페이지에 해당하는 파일은 page.tsx이다.
생성된 폴더들 하위에 page.tsx를 만들면 주소에 해당하는 페이지를 만들 수 있다.
참고로, 트위터에서 특정 유저의 개인페이지는 /{username}이라 [username] 폴더 하위에 page.tsx를 추가해주면 된다!
따라서,
[username]/page.tsx -> 특정 유저의 프로필 화면
[username]/status/[id]/page.tsx -> 특정 유저의 게시글 화면
이 되겠다.
그럼 만약 username이 이미 만들어진 폴더들(home, messages)과 같다면?? -> 정적 라우팅이 우선 적용된다.
username은 해당 폴더명으로 못 만들어지게 해야한다.
Not Found Page (404 페이지)
그리고 next에서는 not found page도 제공한다.
app/not-found.tsx를 생성하면 된다.
미리 만들어둔 페이지가 아닌 경우 나타난다.
# 6. Layout (레이아웃)
Root Layout (최상위 레이아웃)
src/app/layout.tsx
모든 페이지에 적용되는 루트 레이아웃이다.
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={`${geistSans.variable} ${geistMono.variable}`}>
{children}
</body>
</html>
);
}
페이지를 돌아다닐 때마다 page.tsx가 children으로 쏙 들어간다.
특정 페이지에 레이아웃 적용
만약 특정 페이지에서 layout을 따로 적용하고 싶다면?
page.tsx와 같은 레벨에 layout.tsx를 추가하면 된다.
export default async function HomeLayout(
{ children } : Readonly<{ children: React.ReactNode }>) {
return <div>{children}</div>;
}
적용 순서는 이렇게 된다 RootLayout -> HomeLayout -> HomePage
Route Group 을 만들어 로그인 전 / 로그인 후 레이아웃 분리하기
트위터는 로그인 전 레이아웃과 로그인 후 레이아웃이 다르다.
이를 구현하기 위해 Route Group을 활용할 수 있다.
app 폴더 하위에 (afterLogin), (beforeLogin) 폴더 생성
=> 해당 폴더는 라우팅 기능이 없다!
그리고 (afterLogin)/layout.tsx, (beforeLogin)/layout.tsx를 만들어주면
Route Group에 해당하는 페이지들에게 공통된 레이아웃이 적용된다.
Next 서버를 실행시킨 상태로 (afterLogin), (beforeLogin) 폴더를 생성하거나 폴더를 이동하려니 알 수 없는 에러가 났다.. 서버를 껐다가 다시 켜주면 에러는 사라진다.
폴더 이동은 안전하게 서버를 끈 상태로 하자. (Next에서는 폴더 자체가 라우팅이니까?.?)
layout.tsx와 template.tsx
layout.tsx: 페이지가 바뀌어도 리렌더링 되지 않는다.
template.tsx: 페이지가 바뀌면 새롭게 마운트된다.
보통 layout.tsx를 쓰는데.. 언제 template.tsx 쓰나?
=> 페이지 넘나들때마다 무언갈 기록해야할 때 (Ex. 구글 애널리틱스 적용할 때?)
# 7. Next 내장 기능들
next/link
Next에서는 a 태그 대신 next/link를 사용한다.
=> a 태그를 사용하면 페이지가 새로고침 되면서 넘어가기 때문에 next/link를 사용하도록 하자.
next/image
이미지를 렌더링할 때엔 img 태그가 아닌 next/image를 사용한다.
장점은 알아서 최적화 해준다!
이미지 재료를 public 폴더에 넣어주고
import logo from 'path/logo' 로 불러와서 사용하면 된다.
# 8. CSS Module을 사용한 스타일링
스타일링 후보들
스타일링을 할 수 있는 방법은 다양하다.
tailwind -> 호불호 있고 가독성 안 좋음
emotion -> next 13이랑 잘 안맞음
styled component -> 서버 컴포넌트에서 문제 있음 (SSR 이슈)
vanilla extract -> windows와 문제있음ㅋㅋ... (SSR 문제는 없음)
css module -> 간단하다!
CSS Module
import styled from './page.module.css'
styles.{클래스명} 으로 사용
<div>
<div className={styles.left}>
<Image src={zLogo} alt="logo" />
</div>
<div className={styles.right}>
<h1>지금 일어나고 있는 일</h1>
<h2>지금 가입하세요.</h2>
<Link href="/i/flow/signup" className={styles.signup}>
계정 만들기
</Link>
<h3>이미 트위터에 가입하셨나요?</h3>
<Link href="/login" className={styles.login}>
로그인
</Link>
</div>
</div>
css module을 사용한 페이지에서 개발자도구를 켜면
클래스명 뒤에 요상한 문자들이 더 붙어있는 걸 볼 수 있다.
CSS Module을 사용하면 같은 클래스명이라도 다른 모듈로 인식되어 다르게 스타일이 적용될 수 있다.
Global CSS
전역 CSS는 global.css 파일을 사용
=> 전체 페이지에 적용될 공통 스타일은 여기에 작성
# 9. 라우팅 고급 기술 (여긴 너무 어렵다...)
Parallel Routes: 여러 개의 page.tsx를 동시에 보여주기
트위터의 로그인 팝업 화면의 주소는 시작 페이지(/) 주소와 다른데
시작 페이지가 뒤에 남아 있고 로그인 팝업창이 떠있다.
이런건 어떻게 구현할까?
parallel routes를 이용하면
모달창 구현 + history.back() 시 모달창이 닫힌 것처럼 동작하게 구현할 수 있다.
1. (beforeLogin) 폴더 하위에 @modal/page.tsx, layout.tsx, page.tsx 3개 파일 생성
@modal/page.tsx와 page.tsx는 같이 보여주고 싶은 페이지들
2. @modal/page.tsx
export default function Page() {
return "패러랠 모달";
}
3. (beforeLogin)/page.tsx
=> 모달 뒤에 배경으로 둘 페이지
4. (beforeLogin)/layout.tsx
import { ReactNode } from "react";
type Props = {
children: ReactNode;
modal: ReactNode;
};
export default function Layout({ children, modal }: Props) {
return (
<div>
비포 로그인 레이아웃
{children}
{modal}
</div>
);
}
여기서 children은 (beforeLogin)/page.tsx, modal은 @modal/page.tsx가 된다.
@modal이라고 폴더를 생성했기 때문에, layout에서도 modal로 뽑아내야 한다.
modal이 여러개면?
@modal2 폴더 만들고 layout에도 {modal2} 추가하면 된다.
그러나..
여기까지만 하게 되면 / 에 접근했을 때 모달도 같이 뜨게 된다.
@modal/default.tsx 파일을 추가하여
parallel routes가 필요없을 때 동작할 페이지를 정의한다. (parallel routes의 기본값 설정)
export default function Default() {
return null;
}
따라서 위 layout.tsx 파일에서는
// 주소가 localhost:3000일 때는 children -> page.tsx, modal -> @modal/default.tsx
// 주소가 localhost:3000/i/flow/login일 때는 children -> i/flow/login/page.tsx, modal -> @modal/i/flow/login/page.tsx
Intercepting Routes: 라우팅 가로채기
<Link href="/i/flow/login" className={styles.login}>
로그인
</Link>
여기서 Link를 누르면 app/i/flow/login/page.tsx의 내용이 나타난다.
@modal 하위에 있는 page로 인터셉트 하려면
(.)i 폴더를 만든 후 그대로 flow/login을 만든다..
(.)->현재 (..)->부모를 할 수 있는데 브라우저 주소 기준으로 작성해야한다.
(beforeLogin)과 @modal은 주소에 반영되지 않으므로 (.)i로 표시
Parallel Routes와 Intercepting Routes를 사용하여 한 화면에서 모달 띄우기를 완성했다..
라우팅을 가로채고 -> 가로챈 라우팅을 모달로 띄우라...
와 진짜 어렵다
근데???
/i/flow/login에서 새로고침하면 @modal 아래에 인터셉트 라우팅이 적용되지 않는다....
클라이언트에서 라우팅할 때만 인터셉트 라우팅이 적용된다....
진짜 어려워....
Private folder
폴더명 앞에 _(언더바)를 붙인 형태
내부 쓰임용? 폴더다. 공통 파일 정리할 때 사용한다.
주소에 영향이 없는 폴더들
@parallel routes
(라우팅그룹)
(..) (.)
intercepting routes,
_private folder
# 10. 기타
서버 컴포넌트, 클라이언트 컴포넌트
React 18에 도입된 기능으로써 서버 컴포넌트라는 개념이 생겼다.
특징
- 서버 컴포넌트이기 때문에 기본적으로 서버가 사용할 수 있는 기능들을 써먹을 수 있다.
- Next 서버에서 돌아간다.
- 주로 데이터와 관련하여 쓰임
기본적으로 page.tsx 파일은 서버 컴포넌트가 된다.
하지만, 서버 컴포넌트에서는 useState나 useEffect와 같은 hook을 사용하지 못한다.
hook을 사용하기 위해 클라이언트 컴포넌트로 만들어줘야한다!
=> 파일 상단에 'use client' 추가
Page Redirect
page redirect
트위터 페이지에서 로그인 버튼을 누르면 /login -> /i/flow/login으로 리다이렉트 되는 걸 볼 수 있다.
우선 app/(beforeLogin)/login/page.tsx 만들고
next/navigation에서 제공하는 redirect를 사용한다.
import { redirect } from "next/navigation";
export default function LoginPage() {
redirect("/i/flow/login");
}
'개발 > Next.js' 카테고리의 다른 글
[Next 14] 섹션 6 (마지막) (1) | 2024.12.23 |
---|---|
[Next 14] 섹션 5 (1) | 2024.12.09 |
[Next 14] 4. MSW, React-Query, react-intersection-observer (2) | 2024.11.25 |
[Next 14] 3. CSS, Next Hooks, ContextAPI, 외부 라이브러리(faker, dayjs) (2) | 2024.11.11 |
[Next 14] 1. 인트로 (0) | 2024.10.21 |