소스: https://github.com/braverokmc79/nextjs-pages-router-sample
https://nextjs-pages-router-meetup.netlify.app/

477. 몽고 DB 로 작업하기
1 MongoDB Atlas 계정 생성 및 클러스터 설정
- MongoDB Atlas 홈페이지 방문 및 무료 체험 시작: MongoDB Atlas 웹사이트에서 무료 체험 버튼을 클릭하여 계정을 만듭니다.
- 클러스터 생성:
- 기본 설정을 변경하지 않고 진행.
- Free Tier (M0 Sandbox) 선택.
- AWS 및 기본 영역 선택.
- Network Access 설정:
- IP 주소 추가 버튼 클릭.
- 현재 IP 주소 추가.
- Database Access 설정:
- 읽기 및 쓰기 권한을 가진 사용자를 생성
2. Next.js 프로젝트에서 MongoDB와의 연결 설정
- MongoDB 드라이버 설치:
npm install mongodb
3.MongoDB 클러스터와 연결 설정:
- MongoClient를 사용하여 MongoDB 클러스터에 연결.
- 연결 문자열에는 MongoDB Atlas에서 제공한 URI를 사용.
- 연결 시 사용자 이름과 비밀번호 입력.
const { MongoClient } = require('mongodb');
async function connectToDatabase() {
const client = new MongoClient('your_connection_string_here');
try {
await client.connect();
console.log('Connected to database');
const db = client.db('meetups');
const meetupsCollection = db.collection('meetups');
return { client, meetupsCollection };
} catch (error) {
console.error('Connection failed', error);
throw error;
}
}
3. 데이터베이스에 데이터 삽입
- 데이터 삽입 함수 작성:
- 데이터베이스에 문서를 삽입하기 위해 insertOne 메서드 사용.
async function insertMeetup(data) {
const { client, meetupsCollection } = await connectToDatabase();
try {
const result = await meetupsCollection.insertOne(data);
console.log('Meetup inserted:', result.insertedId);
} finally {
await client.close();
}
}
5. API 경로 설정 및 데이터 삽입 API 구현
- API 경로 파일 생성:
- Node.js Express 서버 또는 Next.js API 경로를 사용하여 데이터 삽입 API 작성.
import { MongoClient } from 'mongodb';
async function handler(req, res) {
if (req.method === 'POST') {
const data = req.body;
const client = new MongoClient('your_connection_string_here');
await client.connect();
const db = client.db('meetups');
const meetupsCollection = db.collection('meetups');
const result = await meetupsCollection.insertOne(data);
await client.close();
res.status(201).json({ message: 'Meetup inserted', result });
}
}
export default handler;
6. 클라이언트에서 API 호출
- API 호출 코드 작성:
- 클라이언트 측에서 데이터를 제출하여 API 경로로 요청을 보냄.
async function submitMeetup(meetupData) {
const response = await fetch('/api/new-meetup', {
method: 'POST',
body: JSON.stringify(meetupData),
headers: {
'Content-Type': 'application/json',
},
});
const data = await response.json();
console.log(data);
}
7.요약
MongoDB Atlas 클러스터를 생성하고 next.js 애플리케이션에서 MongoDB 드라이버를 사용하여 클러스터에 연결한 후,
API 경로를 통해 데이터를 삽입할 수 있습니다.
클라이언트 측에서는 API 경로로 요청을 보내어 데이터를 삽입합니다.
이 과정은 MongoDB Atlas 설정, 네트워크 접근 및 데이터베이스 접근 설정,
next.js 프로젝트에서 MongoDB 드라이버 설치 및 사용, 데이터 삽입 함수 작성,
그리고 API 경로 설정 및 클라이언트에서 API 호출로 구성됩니다.
478. API 경로로 Http 요청 보내기
1.Meetup 프로젝트
1)components/meetups/NewMeetupForm.js
import { useRef } from 'react';
import Card from '../ui/Card';
import classes from './NewMeetupForm.module.css';
function NewMeetupForm(props) {
const titleInputRef = useRef();
const imageInputRef = useRef();
const addressInputRef = useRef();
const descriptionInputRef = useRef();
function submitHandler(event) {
event.preventDefault();
const enteredTitle = titleInputRef.current.value;
const enteredImage = imageInputRef.current.value;
const enteredAddress = addressInputRef.current.value;
const enteredDescription = descriptionInputRef.current.value;
const meetupData = {
title: enteredTitle,
image: enteredImage,
address: enteredAddress,
description: enteredDescription,
};
props.onAddMeetup(meetupData);
}
return (
<Card>
<form className={classes.form} onSubmit={submitHandler}>
<div className={classes.control}>
<label htmlFor='title'>Meetup 제목</label>
<input type='text' required id='title' ref={titleInputRef} />
</div>
<div className={classes.control}>
<label htmlFor='image'>Meetup 이미지</label>
<input type='url' required id='image' ref={imageInputRef} />
</div>
<div className={classes.control}>
<label htmlFor='address'>주소</label>
<input type='text' required id='address' ref={addressInputRef} />
</div>
<div className={classes.control}>
<label htmlFor='description'>설명</label>
<textarea
id='description'
required
rows='5'
ref={descriptionInputRef}
></textarea>
</div>
<div className={classes.actions}>
<button>Meetup 추가</button>
</div>
</form>
</Card>
);
}
export default NewMeetupForm;
2)pages/new-meetup/index.js
import NewMeetupForm from "@/components/meetups/NewMeetupForm";
import { useRouter } from "next/router";
function NewMeetupPage() {
const router=useRouter();
async function addMeetupHandler(enteredMeetupData) {
const response=await fetch('/api/new-meetup',{
method: 'POST',
body: JSON.stringify(enteredMeetupData),
headers: {
'Content-Type': 'application/json'
}
});
const data=await response.json();
console.log(data);
router.push("/");
}
return (
<>
<NewMeetupForm onAddMeetup={addMeetupHandler} />
</>
);
}
export default NewMeetupPage;
3)api/new-meetup.js
import { MongoClient } from "mongodb";
// /api/new-meetup
// POST /api/new-meetup
async function handler(req, res) {
if (req.method === "POST") {
const data = req.body;
const clinet = await MongoClient.connect(
"mongodb+srv://아이디:비번@mongo-macaronics.y37mjuf.mongodb.net/meetups?retryWrites=true&w=majority&appName=mongo-macaronics",
{ useNewUrlParser: true }
);
const db = clinet.db();
const meetupsCollection = db.collection("meetups");
const result=await meetupsCollection.insertOne(data);
console.log(result);
clinet.close();
res.status(201).json({message:'Meetup is created successfully'});
}
}
export default handler;
479. 데이터베이스에서 데이터 가져오기
pages/api/db/ConnMongoDB.js
// pages/api/db/ConnMongoDB.js
import { MongoClient } from "mongodb";
export async function ConnMongoDB(){
const clinet = await MongoClient.connect(
"mongodb+srv://아이디:비번@mongo-macaronics.y37mjuf.mongodb.net/meetups?retryWrites=true&w=majority&appName=mongo-macaronics",
{ useNewUrlParser: true }
);
const db = clinet.db();
const meetupsCollection = db.collection("meetups");
return {meetupsCollection, clinet };
}
pages/index.js
import MeetupList from "@/components/meetups/MeetupList";
import { ConnMongoDB } from "./api/db/ConnMongoDB";
const DUMMY_MEETUPS = [
{
id: "m1",
title: "A first meetup",
image:
"https://cdn.pixabay.com/photo/2024/05/11/06/47/tropical-8754092_1280.jpg",
address: "Some address 1",
description: "This is a first meetup",
},
{
id: "m2",
title: "A second meetup",
image:
"https://cdn.pixabay.com/photo/2024/04/08/19/54/coffee-8684315_1280.jpg",
address: "Some address 2",
description: "This is a second meetup",
},
];
function HomePage(props) {
return <MeetupList meetups={props.meetups} />;
}
export async function getStaticProps() {
const { meetupsCollection, clinet } = await ConnMongoDB();
const meetups = await meetupsCollection.find().toArray();
clinet.close();
return {
props: {
meetups: meetups.map(meetup=>({
title:meetup.title,
address:meetup.address,
//description:meetup.description,
image:meetup.image,
id:meetup._id.toString()
})),
},
revalidate: 1,
};
}
export default HomePage;
- ConnMongoDB 함수로 MongoDB에 연결합니다.
- meetupsCollection.find().toArray()를 사용하여 모든 meetup 데이터를 배열로 가져옵니다.
- MongoDB에서 가져온 meetups 데이터를 필요한 속성만 추출하여 props로 설정합니다.
- revalidate는 1초마다 페이지를 새로 고침하여 최신 데이터를 유지합니다.
전체 동작 방식
- Next.js는 getStaticProps 함수를 실행하여 빌드 시 또는 페이지 요청 시 MongoDB에서 데이터를 가져옵니다.
- 가져온 데이터를 HomePage 컴포넌트의 props로 전달합니다.
- HomePage 컴포넌트는 MeetupList 컴포넌트를 사용하여 meetups 데이터를 렌더링합니다.
- revalidate 옵션으로 1초마다 데이터를 새로 고침하여 최신 상태를 유지합니다.
480. Meetup 세 정보 데이터 가져오기 및 페이지 준비하기
pages/[meetupId]/index.js
import MeetupDetail from "@/components/meetups/MeetupDetail";
import { useRouter } from "next/router";
import { ConnMongoDB } from "../api/db/ConnMongoDB";
import { ObjectId } from "mongodb";
function MeetUpDeailPage(props) {
const router = useRouter();
if (router.isFallback) {
return <p>Loading...</p>;
}
const { id, image, title, address, description}= props.meetupData;
return (
<MeetupDetail
id={id}
title={title}
image={image}
address={address}
description={description}
/>
);
}
export async function getStaticPaths() {
const {meetupsCollection, client } =await ConnMongoDB();
const meetups=await meetupsCollection.find({}, { _id: 1}).toArray();
client.close();
return {
fallback: false,
paths: meetups.map(meetup => ({params :{meetupId : meetup._id.toString() }}))
}
// return {
// fallback: false,
// paths: [
// {
// params: {
// meetupId: "m1",
// },
// },
// {
// params: {
// meetupId: "m2",
// },
// },
// ],
//};
}
export async function getStaticProps(context) {
const meetupId = context.params.meetupId;
const {meetupsCollection, client } =await ConnMongoDB();
const selectedMeetup = await meetupsCollection.findOne({ _id: new ObjectId(meetupId) });
client.close();
return {
props:{
meetupData: {
id:selectedMeetup._id.toString(),
title:selectedMeetup.title,
image:selectedMeetup.image,
address:selectedMeetup.address,
description:selectedMeetup.description,
},
revalidate: 1,
}
}
// return {
// props: {
// meetupData: {
// title: "A second meetup",
// image:
// "https://cdn.pixabay.com/photo/2024/04/08/19/54/coffee-8684315_1280.jpg",
// address: "Some address 2",
// description: "This is a second meetup",
// id: meetupId,
// },
// revalidate: 1,
// },
// };
}
export default MeetUpDeailPage;
구성 요소 및 기능 설명
1. MeetupDetail 컴포넌트
- Meetup의 세부 정보를 표시하는 컴포넌트입니다. @/components/meetups/MeetupDetail 경로에서 가져옵니다.
import MeetupDetail from "@/components/meetups/MeetupDetail";
2. useRouter 훅
- Next.js의 useRouter 훅을 사용하여 라우팅과 관련된 기능을 제공합니다.
- router.isFallback을 사용하여 빌드 시 경로가 아직 생성되지 않은 경우 로딩 상태를 처리합니다.
import { useRouter } from "next/router";
3. ConnMongoDB 함수
- MongoDB에 연결하는 함수입니다. ../api/db/ConnMongoDB 경로에서 가져옵니다.
import { ConnMongoDB } from "../api/db/ConnMongoDB";
4. ObjectId 클래스
- MongoDB에서 문서의 _id 필드를 다루기 위해 mongodb 패키지에서 ObjectId를 가져옵니다.
import { ObjectId } from "mongodb";
5. MeetUpDeailPage 컴포넌트
- 특정 meetup의 세부 정보를 렌더링하는 페이지 컴포넌트입니다.
- router.isFallback을 사용하여 로딩 상태를 처리합니다.
function MeetUpDeailPage(props) {
const router = useRouter();
if (router.isFallback) {
return <p>Loading...</p>;
}
const { id, image, title, address, description } = props.meetupData;
return (
<MeetupDetail
id={id}
title={title}
image={image}
address={address}
description={description}
/>
);
}
6. getStaticPaths 함수
- Next.js의 getStaticPaths를 사용하여 정적 생성할 경로를 정의합니다.
- MongoDB에서 모든 meetup의 _id를 가져와 paths를 생성합니다.
export async function getStaticPaths() {
const { meetupsCollection, client } = await ConnMongoDB();
const meetups = await meetupsCollection.find({}, { _id: 1 }).toArray();
client.close();
return {
fallback: false,
paths: meetups.map(meetup => ({
params: { meetupId: meetup._id.toString() }
}))
};
}
- fallback: false로 설정하면, 지정된 경로 외의 다른 경로는 404 페이지를 표시합니다.
- 모든 meetup의 _id를 가져와 params 객체로 변환하여 paths를 생성합니다.
7. getStaticProps 함수
- Next.js의 getStaticProps를 사용하여 빌드 시 meetup 데이터를 가져와 props로 전달합니다.
- context.params를 통해 동적 경로 매개변수를 가져옵니다.
export async function getStaticProps(context) {
const meetupId = context.params.meetupId;
const { meetupsCollection, client } = await ConnMongoDB();
const selectedMeetup = await meetupsCollection.findOne({ _id: new ObjectId(meetupId) });
client.close();
return {
props: {
meetupData: {
id: selectedMeetup._id.toString(),
title: selectedMeetup.title,
image: selectedMeetup.image,
address: selectedMeetup.address,
description: selectedMeetup.description,
},
revalidate: 1,
}
};
}
- context.params.meetupId를 사용하여 특정 meetup의 ID를 가져옵니다.
- MongoDB에서 해당 ID를 가진 meetup 데이터를 찾고, 필요한 정보를 props로 전달합니다.
- revalidate를 통해 1초마다 페이지를 다시 생성하여 최신 데이터를 유지합니다.
전체 동작 방식
정적 경로 생성 (getStaticPaths):
- MongoDB에서 모든 meetup의 ID를 가져와 paths를 생성합니다.
- fallback: false로 설정하여 지정된 경로 외의 다른 경로는 404 페이지를 표시합니다.
정적 데이터 생성 (getStaticProps):
- context.params.meetupId를 사용하여 특정 meetup의 데이터를 MongoDB에서 가져옵니다.
- 가져온 데이터를 props로 설정하여 MeetUpDeailPage 컴포넌트에 전달합니다.
- 1초마다 페이지를 다시 생성하여 최신 데이터를 유지합니다.
페이지 렌더링 (MeetUpDeailPage):
- useRouter를 사용하여 라우팅과 로딩 상태를 처리합니다.
- props로 전달받은 데이터를 MeetupDetail 컴포넌트에 전달하여 meetup의 세부 정보를 렌더링합니다.
이를 통해 사용자는 특정 meetup의 세부 정보를 볼 수 있으며, 데이터는 MongoDB에서 가져와 최신 상태를 유지합니다.
481. "head" 메타 데이터 추가하기
pages/[meetupId]/index.js
return (
<Fragment>
<Head>
<title>{title}</title>
<meta name="description" content={description} />
</Head>
<MeetupDetail
id={id}
title={title}
image={image}
address={address}
description={description}
/>
</Fragment>
);
1. next/head 모듈 임포트
먼저 next/head 모듈을 페이지 컴포넌트에 임포트합니다.
import Head from 'next/head';
2. Head 컴포넌트 사용
Head 컴포넌트를 사용하여 메타데이터를 추가합니다. 예를 들어, 제목과 메타 태그를 추가하는 방법은 다음과 같습니다.
import Head from 'next/head';
function HomePage() {
return (
<>
<Head>
<title>My Awesome Meetup</title>
<meta name="description" content="This is a description of my awesome meetup page." />
<meta property="og:title" content="My Awesome Meetup" />
<meta property="og:description" content="This is a description of my awesome meetup page." />
<meta property="og:image" content="/images/meetup-image.jpg" />
<meta property="og:url" content="https://myawesomewebsite.com/meetup" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
{/* 페이지 내용 */}
</main>
</>
);
}
export default HomePage;
설명
- Head 컴포넌트: Head 컴포넌트 안에 모든 메타데이터 태그를 추가합니다.
- <title> 태그: 페이지의 제목을 설정합니다.
- 메타 태그들:
- <meta name="description" ... />: 페이지 설명을 설정합니다.
- <meta property="og:title" ... />: Open Graph 제목을 설정합니다 (소셜 미디어 공유 시).
- <meta property="og:description" ... />: Open Graph 설명을 설정합니다.
- <meta property="og:image" ... />: Open Graph 이미지 URL을 설정합니다.
- <meta property="og:url" ... />: Open Graph URL을 설정합니다.
- <meta name="twitter:card" ... />: Twitter 카드 타입을 설정합니다.
- 파비콘: <link rel="icon" href="/favicon.ico" />를 사용하여 파비콘을 설정합니다.
이렇게 하면 해당 페이지를 렌더링할 때, Next.js가 <head> 섹션에 지정한 메타데이터를 포함하게 됩니다.
동적 메타데이터
동적 메타데이터를 설정하려면 getStaticProps 또는 getServerSideProps를 사용하여 데이터를 가져온 후, 해당 데이터를 Head 컴포넌트에 사용합니다.
import Head from 'next/head';
import { ConnMongoDB } from './api/db/ConnMongoDB';
function MeetupDetailPage({ meetupData }) {
return (
<>
<Head>
<title>{meetupData.title}</title>
<meta name="description" content={meetupData.description} />
<meta property="og:title" content={meetupData.title} />
<meta property="og:description" content={meetupData.description} />
<meta property="og:image" content={meetupData.image} />
<meta property="og:url" content={`https://myawesomewebsite.com/meetup/${meetupData.id}`} />
<meta name="twitter:card" content="summary_large_image" />
</Head>
<main>
{/* 페이지 내용 */}
</main>
</>
);
}
export async function getStaticProps(context) {
const meetupId = context.params.meetupId;
const { meetupsCollection, client } = await ConnMongoDB();
const selectedMeetup = await meetupsCollection.findOne({ _id: new ObjectId(meetupId) });
client.close();
return {
props: {
meetupData: {
id: selectedMeetup._id.toString(),
title: selectedMeetup.title,
image: selectedMeetup.image,
address: selectedMeetup.address,
description: selectedMeetup.description,
},
},
revalidate: 1,
};
}
export default MeetupDetailPage;
이렇게 하면 동적으로 데이터를 가져와 <head> 섹션에 반영할 수 있습니다.
482. Next.js 프로젝트 배포하기
1. Vercel 계정 생성 및 로그인
- Vercel 웹사이트로 이동합니다.
- 계정이 없으면 "Sign Up" 버튼을 클릭하여 가입합니다.
- GitHub, GitLab, Bitbucket 계정으로 가입 및 로그인할 수 있습니다.
- 이미 계정이 있다면 "Login" 버튼을 클릭하여 로그인합니다.
2. Next.js 프로젝트 준비
Next.js 프로젝트가 없는 경우, 다음 명령어로 새로운 프로젝트를 생성할 수 있습니다:
npx create-next-app my-next-app cd my-next-app
3. Git 저장소에 프로젝트 푸시
- Git 저장소를 생성합니다 (GitHub, GitLab 또는 Bitbucket에서).
- 로컬 프로젝트 디렉토리에서 Git 초기화 및 원격 저장소에 프로젝트를 푸시합니다.
git init git add . git commit -m "Initial commit" git remote add origin <your-repository-url> git push -u origin main
4. Vercel에서 새로운 프로젝트 생성
- Vercel 대시보드에서 "New Project" 버튼을 클릭합니다.
- Git 제공자(GitHub, GitLab, Bitbucket)와 연결하여 배포할 저장소를 선택합니다.
5. 프로젝트 임포트
- 배포할 저장소를 선택한 후 "Import" 버튼을 클릭합니다.
- Vercel이 자동으로 프로젝트 설정을 감지합니다. 기본적으로 설정된 값을 사용할 수 있습니다.
6. 빌드 설정 확인
Vercel은 Next.js 프로젝트를 자동으로 인식하고 기본 빌드 설정을 적용합니다.
- Build Command: next build
- Output Directory: .next
특정 설정이 필요한 경우 이 단계에서 수정할 수 있습니다.
7. 환경 변수 설정 (필요한 경우)
프로젝트에 필요한 환경 변수가 있다면 Vercel 대시보드에서 설정할 수 있습니다.
- Vercel 대시보드에서 배포된 프로젝트를 선택합니다.
- "Settings" 탭으로 이동합니다.
- "Environment Variables" 섹션에서 환경 변수를 추가합니다.
8. 배포 트리거
- 프로젝트를 Vercel에 연결하고 저장소에 푸시하면 자동으로 배포가 트리거됩니다.
- 모든 푸시마다 Vercel이 프로젝트를 다시 빌드하고 배포합니다.
git add . git commit -m "Update project" git push origin main
9. 배포 확인
- 배포가 완료되면 Vercel 대시보드에서 프로젝트의 URL을 확인할 수 있습니다.
- 제공된 URL을 방문하여 Next.js 애플리케이션이 올바르게 작동하는지 확인합니다.
10. 추가 설정 및 관리
- 도메인 연결: Vercel 대시보드에서 사용자 정의 도메인을 프로젝트에 연결할 수 있습니다.
- "Domains" 탭에서 도메인을 추가하고 설정을 완료합니다.
- 배포 미리보기: PR을 생성하면 Vercel이 자동으로 미리보기 URL을 생성하여 변경 사항을 확인할 수 있습니다.
- 프로젝트 설정: "Settings" 탭에서 프로젝트의 기타 설정을 관리할 수 있습니다.
도메인 설정
- Vercel 대시보드에서 프로젝트를 선택합니다.
- "Settings" 탭으로 이동하여 "Domains" 섹션으로 스크롤합니다.
- "Add Domain" 버튼을 클릭하고 사용자 정의 도메인을 입력합니다.
- 도메인 제공자의 DNS 설정에서 Vercel이 제공하는 CNAME 또는 A 레코드를 추가합니다.
지속적인 배포
Vercel은 기본적으로 지속적인 배포를 지원합니다. 코드 변경 사항을 Git 저장소에 푸시하면 Vercel이 자동으로 빌드 및 배포를 트리거합니다.
git add . git commit -m "Update project" git push origin main
이 과정을 통해 Next.js 애플리케이션을 Vercel을 통해 쉽게 배포하고 관리할 수 있습니다.
Vercel의 강력한 기능과 간편한 사용법 덕분에 빠르게 프로덕션 수준의 웹사이트를 운영할 수 있습니다.














댓글 ( 0)
댓글 남기기