https://www.youtube.com/watch?v=smAU6-ZdcoQ&list=PLuHgQVnccGMCwxXsQuEoG-JJ7RlwtNdwJ&index=2
폴더 만든 후
폴더 안으로 이동해서
npx create-next-app@latest . (마침표)
npm notice
npm notice New patch version of npm available! 10.2.3 -> 10.2.4
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.2.4
npm notice Run npm install -g npm@10.2.4 to update!
npm notice
npm ERR! code ENOENT
npm ERR! syscall lstat
npm ERR! path C:\Users\newstep\AppData\Roaming\npm
npm ERR! errno -4058
npm ERR! enoent ENOENT: no such file or directory, lstat 'C:\Users\newstep\AppData\Roaming\npm'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent
npm ERR! A complete log of this run can be found in: C:\Users\newstep\AppData\Local\npm-cache\_logs\2023-11-29T03_08_56_789Z-debug-0.log
npm install -g npm@10.2.4
npx create-next-app@latest . (마침표)
Ok to proceed? (y) y
? Would you like to use TypeScript? » No / Yes 노 엔터
√ Would you like to use ESLint? ... No / Yes 예스 엔터
√ Would you like to use Tailwind CSS? ... No / Yes 예스 엔터
√ Would you like to use `src/` directory? ... No / Yes 예스 엔터
? Would you like to use App Router? (recommended) » No / Yes 예스 엔터
? Would you like to customize the default import alias (@/*)? » No / Yes 노 엔터
설치 완료 후
개발환경 실행
npm run dev
실행되면
크롬으로 http://localhost:3000
접속하면 됨
https://www.youtube.com/watch?v=siBQ-y84ZO0&list=PLuHgQVnccGMCwxXsQuEoG-JJ7RlwtNdwJ&index=3
src\app\layout.js--------------------샘플 웹페이지 리모델링
import './globals.css'
export const metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
export default function RootLayout({ children }) {
return (
<html>
<body>{children}</body>
</html>
)
}
src\app\page.js --------------------children
import Image from 'next/image'
export default function Home() {
return (
<>Hello 안녕, Next.js</>
)
}
src\app\globals.css --------------------내용지우기
https://www.youtube.com/watch?v=WuhJN-_pWfI&list=PLuHgQVnccGMCwxXsQuEoG-JJ7RlwtNdwJ&index=4
package.json--------------------
{
"name": "next",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"react": "^18",
"react-dom": "^18",
"next": "14.0.3"
},
"devDependencies": {
"autoprefixer": "^10.0.1",
"postcss": "^8",
"tailwindcss": "^3.3.0",
"eslint": "^8",
"eslint-config-next": "14.0.3"
}
}
node.js 기반 프로젝트들은
Scripts 안에 프로젝트를 유지 보수 하기위한 여러가지 명령들을 갖고 있다
npm run dev 라고 하면
가 실행 되는 것이다
실서버를 위한 배포 명령은
배포판을 서비스 시작하는 명령은
서버 끄기 Ctrl+C
배포명령
npm run build
.next폴더에 배포판이 만들어진다
배포판 실행하려면
npm run start
크롬으로 http://localhost:3000
접속하면 됨 (네트워크 탭에서 전송된 데이터량을 보면 엄청 줄어든 것을 알 수 있다)
https://www.youtube.com/watch?v=4xEw3Nz5hTY&list=PLuHgQVnccGMCwxXsQuEoG-JJ7RlwtNdwJ&index=5
서버 끄기 Ctrl+C
개발서버 실행
npm run dev
src\app\page.js --------------------
import Image from 'next/image'
export default function Home() {
return (
<>
<h2>Welcome</h2>
Hello, WEB!
</>
)
}
src\app\layout.js --------------------
import './globals.css'
export const metadata = {
title: 'Web tutorials',
description: 'Generated by egoing',
}
export default function RootLayout({ children }) {
return (
<html>
<body>
<h1><a href='/'>WEB</a></h1>
<ol>
<li><a href='/read/1'>html</a></li>
<li><a href='/read/2'>css</a></li>
</ol>
<hr />
{children}
<hr />
<ul>
<li><a href='/create'>Create</a></li>
<li><a href='/update/1'>Update</a></li>
<li><input type='button' value='delete' /></li>
</ul>
</body>
</html>
)
}
https://www.youtube.com/watch?v=xE-GT8gjgJw&list=PLuHgQVnccGMCwxXsQuEoG-JJ7RlwtNdwJ&index=6
src\app\create\page.js--------------------폴더 만들고 파일도 만들자
export default function Create(){
return (
<>Create!!</>
)
}
src\app\create\layout.js--------------------
export default function Layout(props){
return (
<form>
<h2>Create</h2>
<hr />
<hr />
{props.children}
<hr />
<hr />
</form>
)
}
다이나믹 라우터
src\app\read\[id]\page.js --------------------
export default function Read(props){
return (
<>
<h2>Read!!</h2>
parameters : {props.params.id}
</>
)
}
https://www.youtube.com/watch?v=en-OkqU-agI&list=PLuHgQVnccGMCwxXsQuEoG-JJ7RlwtNdwJ&index=7
enable javascript
src\app\layout.js --------------------
import Link from 'next/link'
import './globals.css'
export const metadata = {
title: 'Web tutorials',
description: 'Generated by egoing',
}
export default function RootLayout({ children }) {
return (
<html>
<body>
<h1><Link href='/'>WEB</Link></h1> {/* 수정 */}
<ol>
<li><Link href='/read/1'>html</Link></li> {/* 수정 */}
<li><Link href='/read/2'>css</Link></li> {/* 수정 */}
</ol>
<hr />
{children}
<hr />
<ul>
<li><Link href='/create'>Create</Link></li> {/* 수정 */}
<li><Link href='/update/1'>Update</Link></li> {/* 수정 */}
<li><input type='button' value='delete' /></li>
</ul>
</body>
</html>
)
}
https://www.youtube.com/watch?v=Ypkm0s69FTM&list=PLuHgQVnccGMCwxXsQuEoG-JJ7RlwtNdwJ&index=8
public폴더에 hello.png 넣기
src\app\page.js --------------------
import Image from 'next/image'
export default function Home() {
return (
<>
<h2>Welcome</h2>
Hello, WEB!
<br />
<img src='/hello.png'></img>
</>
)
}
https://www.youtube.com/watch?v=9TdWS8fmcRo&list=PLuHgQVnccGMCwxXsQuEoG-JJ7RlwtNdwJ&index=9
src\app\globals.css --------------------
h1 a {
text-decoration: none;
}
https://www.youtube.com/watch?v=WhTB0q1nvDM&list=PLuHgQVnccGMCwxXsQuEoG-JJ7RlwtNdwJ&index=10
npx json-server --port 9999 --watch db.json
db.json --------------------
{
"posts": [
{
"id": 1,
"title": "json-server",
"author": "typicode"
}
],
"comments": [
{
"id": 1,
"body": "some comment",
"postId": 1
}
],
"profile": {
"name": "typicode"
}
}
크롬으로 http://localhost:9999/posts 접속하면 아래와 같이 리턴됨
// 20231129161153
// http://localhost:9999/posts
[
{
"id": 1,
"title": "json-server",
"author": "typicode"
}
]
db.json -------------------- 수정
{
"topics": [
{"id": 1, "title": "html", "body": "html is ..."},
{"id": 2, "title": "css", "body": "css is ..."}
],
"posts": [
{
"id": 1,
"title": "json-server",
"author": "typicode"
}
],
"comments": [
{
"id": 1,
"body": "some comment",
"postId": 1
}
],
"profile": {
"name": "typicode"
}
}
크롬으로 http://localhost:9999/topics 접속하면 아래와 같이 리턴됨
// 20231129161746
// http://localhost:9999/topics
[
{
"id": 1,
"title": "html",
"body": "html is ..."
},
{
"id": 2,
"title": "css",
"body": "css is ..."
}
]
크롬에서 개발자도구-네트워크
esc 클릭
console창 클릭 (서버 통신에 사용하는 fetch 명령으로 json 데이터 가져오자)
fetch('http://localhost:9999/topics')
.then((resp)=>{
return resp.json();
})
.then((result)=>{
console.log('result', result);
});
결과
https://www.youtube.com/watch?v=t-Jt961oNeg&list=PLuHgQVnccGMCwxXsQuEoG-JJ7RlwtNdwJ&index=11
클라이언트로 작업하면 비효율적
서버에서 데이터를 가져오기 위해서는 useEffect()가 필요
한 번만 실행하게 빈 배열을 넣는다
layout.js --------------------
import Link from 'next/link'
import './globals.css'
import { useEffect, useState } from 'react'
export const metadata = {
title: 'Web tutorials',
description: 'Generated by egoing',
}
export default function RootLayout({ children }) {
const [topics, setTopics] = useState([]);{/* 빈 배열 */}
useEffect(()=>{
fetch('http://localhost:9999/topics')
.then(resp=>resp.json())
.then(result=>{
setTopics(result);
});
},[]);
return (
<html>
<body>
<h1><Link href='/'>WEB</Link></h1> {/* 수정 */}
<ol>
<li><Link href='/read/1'>html</Link></li> {/* 수정 */}
<li><Link href='/read/2'>css</Link></li> {/* 수정 */}
</ol>
<hr />
{children}
<hr />
<ul>
<li><Link href='/create'>Create</Link></li> {/* 수정 */}
<li><Link href='/update/1'>Update</Link></li> {/* 수정 */}
<li><input type='button' value='delete' /></li>
</ul>
</body>
</html>
)
}
layout.js --------------------
"use client";
import Link from 'next/link'
import './globals.css'
import { useEffect, useState } from 'react'
export const metadata = {
title: 'Web tutorials',
description: 'Generated by egoing',
}
export default function RootLayout({ children }) {
const [topics, setTopics] = useState([]);{/* 빈 배열 */}
useEffect(()=>{
fetch('http://localhost:9999/topics')
.then(resp=>resp.json())
.then(result=>{
setTopics(result);
});
},[]);
return (
<html>
<body>
<h1><Link href='/'>WEB</Link></h1> {/* 수정 */}
<ol>
<li><Link href='/read/1'>html</Link></li> {/* 수정 */}
<li><Link href='/read/2'>css</Link></li> {/* 수정 */}
</ol>
<hr />
{children}
<hr />
<ul>
<li><Link href='/create'>Create</Link></li> {/* 수정 */}
<li><Link href='/update/1'>Update</Link></li> {/* 수정 */}
<li><input type='button' value='delete' /></li>
</ul>
</body>
</html>
)
}
layout.js --------------------
"use client";
import Link from 'next/link'
import './globals.css'
import { useEffect, useState } from 'react'
// export const metadata = {
// title: 'Web tutorials',
// description: 'Generated by egoing',
// }
export default function RootLayout({ children }) {
const [topics, setTopics] = useState([]);{/* 빈 배열 */}
useEffect(()=>{
fetch('http://localhost:9999/topics')
.then(resp=>resp.json())
.then(result=>{
setTopics(result);
});
},[]);
return (
<html>
<body>
<h1><Link href='/'>WEB</Link></h1> {/* 수정 */}
<ol>
<li><Link href='/read/1'>html</Link></li> {/* 수정 */}
<li><Link href='/read/2'>css</Link></li> {/* 수정 */}
</ol>
<hr />
{children}
<hr />
<ul>
<li><Link href='/create'>Create</Link></li> {/* 수정 */}
<li><Link href='/update/1'>Update</Link></li> {/* 수정 */}
<li><input type='button' value='delete' /></li>
</ul>
</body>
</html>
)
}
layout.js --------------------
"use client";
import Link from 'next/link'
import './globals.css'
import { useEffect, useState } from 'react'
// export const metadata = {
// title: 'Web tutorials',
// description: 'Generated by egoing',
// }
export default function RootLayout({ children }) {
const [topics, setTopics] = useState([]);{/* 빈 배열 */}
useEffect(()=>{
fetch('http://localhost:9999/topics')
.then(resp=>resp.json())
.then(result=>{
setTopics(result);
});
},[]);
return (
<html>
<body>
<h1><Link href='/'>WEB</Link></h1>
<ol>
<li><Link href='/read/1'>html</Link></li>
<li><Link href='/read/2'>css</Link></li>
</ol>
<hr />
{children}
<hr />
<ul>
<li><Link href='/create'>Create</Link></li>
<li><Link href='/update/1'>Update</Link></li>
<li><input type='button' value='delete' /></li>
</ul>
</body>
</html>
)
}
topics로 글목록 만들기
npx json-server --port 9999 --watch db.json
npm run dev
아쉬운 점들
서버가 원격에 있다면 데이터를 가져오는데 시간이 걸린다
useEffect(()=>{
fetch('http://localhost:9999/topics')
.then(resp=>resp.json())
.then(result=>{
setTopics(result);
});
},[]);
서버컨퍼넌트로 바꾸려면
layout.js --------------------
import Link from 'next/link'
import './globals.css'
import { useEffect, useState } from 'react'
// export const metadata = {
// title: 'Web tutorials',
// description: 'Generated by egoing',
// }
export default function RootLayout({ children }) {
const [topics, setTopics] = useState([]);{/* 빈 배열 */}
useEffect(()=>{
fetch('http://localhost:9999/topics')
.then(resp=>resp.json())
.then(result=>{
setTopics(result);
});
},[]);
return (
<html>
<body>
<h1><Link href='/'>WEB</Link></h1>
<ol>
{topics.map((topic)=>{
return <li key={topic.id}><Link href={`/read/${topic.id}`}>{topic.title}</Link></li>
})}
</ol>
<hr />
{children}
<hr />
<ul>
<li><Link href='/create'>Create</Link></li>
<li><Link href='/update/1'>Update</Link></li>
<li><input type='button' value='delete' /></li>
</ul>
</body>
</html>
)
}
"use client" 없으면 되는데
여기에서 에러나는 이유는 useState, useEffect 사용해서 그렇다
layout.js --------------------
import Link from 'next/link'
import './globals.css'
export const metadata = {
title: 'Web tutorials',
description: 'Generated by egoing',
}
export default async function RootLayout({ children }) {
const resp = await fetch('http://localhost:9999/topics');
const topics = await resp.json();
return (
<html>
<body>
<h1><Link href='/'>WEB</Link></h1>
<ol>
{topics.map((topic)=>{
return <li key={topic.id}><Link href={`/read/${topic.id}`}>{topic.title}</Link></li>
})}
</ol>
<hr />
{children}
<hr />
<ul>
<li><Link href='/create'>Create</Link></li>
<li><Link href='/update/1'>Update</Link></li>
<li><input type='button' value='delete' /></li>
</ul>
</body>
</html>
)
}
https://www.youtube.com/watch?v=nHCBiiTYma4&list=PLuHgQVnccGMCwxXsQuEoG-JJ7RlwtNdwJ&index=12
src\app\read\[id]\page.js --------------------
export default async function Read(props){
const resp = await fetch(`http://localhost:9999/topics/${props.params.id}`)
const topic = await resp.json();
return (
<>
<h2>{topic.title}</h2>
{topic.body}
</>
)
}
https://www.youtube.com/watch?v=esmAbm-UyB4&list=PLuHgQVnccGMCwxXsQuEoG-JJ7RlwtNdwJ&index=13
src\app\create\layout.js 필요 없으니까 지우자
혹시 에러날 경우
rm -rf .next
npm run dev
하면 새로 만들어줌
submit 누르면 페이지전환 되는데 이를 방지하기위해서
e.preventDefault();
title과 body 값 알아내기
src\app\create\page.js --------------------
"use client"
import { useRouter } from "next/navigation";
export default function Create(){
const router = useRouter();
return (
<form onSubmit={(e)=>{
e.preventDefault();
const title = e.target.title.value;
const body = e.target.body.value;
const options = {
method: 'POST',
Headers: {
'Content-Type': 'application/json'
},
body : JSON.stringify({title, body})
}
fetch(`http://localhost:9999/topics`, options)
.then(res=>res.json())
.then(result=>{
console.log(result);
const lastid = result.id;
router.push(`/read/${lastid}`);
})
}}>
<p>
<input type="text" name="title" placeholder="title" />
</p>
<p>
<textarea name="body" placeholder="body"></textarea>
</p>
<p>
<input type="submit" value="create" />
</p>
</form>
)
}
http://localhost:3000/create
데이터 입력
javascript
create 버튼 클릭
react
create 버튼 클릭
'컴퓨터 > nextjs' 카테고리의 다른 글
nextjs-app 만들기 (0) | 2025.02.19 |
---|