Skip to content

Commit 4839c62

Browse files
committed
update post
1 parent 57a5cf9 commit 4839c62

11 files changed

+266
-16
lines changed

content/posts/영역/개발/내가 1년간의 리눅스 개발 여정을 끝내고 윈도우와 맥으로 돌아온 이유.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ tags:
33
- area
44
- 개발
55
createdAt: 2025-06-14 18:33:27
6-
modifiedAt: 2025-06-14 19:17:57
6+
modifiedAt: 2025-06-30 08:59:46
77
publish: 영역/개발
88
related: ""
99
series: ""

content/posts/자원/Linux/Linux에서 Onedrive 사용하기.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ tags:
55
- onedrive
66
- wsl
77
createdAt: 2025-06-07 13:01:39
8-
modifiedAt: 2025-06-12 16:34:24
8+
modifiedAt: 2025-06-30 09:27:08
99
publish: 자원/Linux
1010
related: ""
1111
series: ""
@@ -70,6 +70,16 @@ monitor_interval = "300"
7070
앱/remotely-save/notes
7171
```
7272

73+
> [!tip] Obsidian과의 싱크를 위해 사용할 때 필수 옵션
74+
>
75+
> Onedrive를 --monitor 모드로 사용하여 Obsidian 파일들을 지속적으로 수정하게 되면 계속해서 `inotify` 이벤트를 받게되고 이는 지속적인 재업로드를 유발한다. 이 때문에 파일이 충돌이 나는 경우가 생겨 백업파일을 만들거나 파일이 삭제 되기도 한다.
76+
> 이것을 방지하기 위해 아래의 두 옵션을 사용하는것이 좋다.
77+
>
78+
> ```config
79+
> force_session_upload = "true"
80+
> delay_inotify_processing = "true"
81+
> ```
82+
7383
## 지속적으로 동기화하기
7484
7585
다음 명령어를 통해 지속적으로 동기화 할 수 있다.

content/posts/저장소/아임유어박스 웹사이트/물류 서비스 웹사이트 개발 회고-혼자서 외주 프로젝트 완성하기.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ tags:
44
- 회고
55
- portfolio
66
createdAt: 2025-03-25 16:46:50
7-
modifiedAt: 2025-06-17 14:31:02
7+
modifiedAt: 2025-06-30 13:18:05
88
publish: 프로젝트/아임유어박스 웹사이트
99
related: ""
1010
series: ""

content/posts/프로젝트/당근마켓 클론코딩/당근마켓 클론코딩.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ tags:
55
- study
66
- clone
77
createdAt: 2025-06-13 11:29:34
8-
modifiedAt: 2025-06-17 22:24:43
8+
modifiedAt: 2025-06-30 15:17:53
99
publish: 프로젝트/당근마켓 클론코딩
1010
related: ""
1111
series: ""
@@ -34,3 +34,4 @@ next.js로 프로젝트를 생성한다.
3434
기본 셋업을 통해 프로젝트를 생성하면 기본적으로 tailwindcss가 설치되어 기본적으로 사용할 수 있다.
3535

3636
- [[당근마켓 클론코딩으로 기본적인 tailwind 복습하기]]
37+
- [[당근마켓 클론코딩으로 기본적인 next.js 복습하기]]
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
---
2+
tags:
3+
- project
4+
- carrot-market
5+
- study
6+
createdAt: 2025-06-30 08:48:51
7+
modifiedAt: 2025-06-30 21:16:46
8+
publish: 프로젝트/당근마켓 클론코딩
9+
related: ""
10+
series: ""
11+
---
12+
13+
# 당근마켓 클론코딩으로 기본적인 Next.js 복습하기
14+
15+
## 앱 라우터 기본 구조
16+
17+
Next.js는 폴더구조를 총해 라우트 경로를 정의한다.
18+
`app`폴더 내에 원하는 경로 이름으로 폴더를 생성하고 해당 폴더 안에 `page.tsx`파일을 만들고 정의하면 된다.
19+
20+
```bash
21+
my-next-app/
22+
├── app/
23+
│ ├── layout.tsx # 공통 레이아웃
24+
│ ├── page.tsx # 메인 페이지
25+
│ ├── globals.css # 전역 CSS
26+
│ └── ... # 추가 라우트 및 컴포넌트
27+
├── public/
28+
│ ├── favicon.ico # 파비콘
29+
│ └── vercel.svg # 이미지 등 정적 파일
30+
├── node_modules/ # 설치된 패키지
31+
├── .next/ # 빌드 결과물
32+
├── .gitignore # Git 추적 제외 파일 목록
33+
├── next.config.mjs # Next.js 설정 파일
34+
├── package.json # 프로젝트 정보 및 의존성 관리
35+
└── tsconfig.json # 타입스크립트 설정 파일
36+
```
37+
38+
- `app/`: 애플리케이션의 모든 라우트, 컴포넌트, 로직이 위치하는 핵심 디렉토리.
39+
40+
- `layout.tsx`: 모든 페이지에 공통으로 적용되는 최상위 레이아웃. `<html>`, `<body>` 태그를 포함.
41+
- `page.tsx`: 특정 경로의 UI를 정의하는 기본 페이지 파일. app/page.tsx는 루트 경로(/)에 해당.
42+
- `loading.tsx`: 해당 경로의 콘텐츠가 로드되는 동안 보여줄 로딩 UI.
43+
- `error.tsx`: 해당 경로에서 에러가 발생했을 때 보여줄 에러 UI.
44+
- `route.ts`: 서버 사이드 API 엔드포인트 (API Routes)를 생성할 때 사용.
45+
46+
- `public/`: 이미지, 폰트 등 정적(Static) 파일들을 저장하는 공간. 이곳의 파일들은 웹사이트의 루트 경로(/)를 통해 직접 접근할 수 있다.
47+
48+
- `next.config.mjs`: Next.js의 고급 설정을 변경할 때 사용하는 파일. 예를 들어, 이미지 최적화 설정, 환경 변수 추가, 리다이렉트 설정 등을 할 수 있다.
49+
50+
`package.json`: 프로젝트의 이름, 버전과 같은 정보와 함께 react, next 등 프로젝트가 사용하는 라이브러리(의존성) 목록을 관리.
51+
52+
### 페이지
53+
54+
`page.tsx` 파일 안에 리엑트 함수 형식으로 정의하면 `page.tsx`가 존재하는 파일 구조에 대한 라우팅이 자동으로 설정된다.
55+
중요한 점은 `export default` 처리를 해주어야 한다는 것이다.
56+
57+
```tsx
58+
export default function Home() {
59+
return <div>메인 페이지</div>;
60+
}
61+
```
62+
63+
```tsx
64+
const Home = () => {
65+
return <div>메인 페이지</div>;
66+
};
67+
export default Home;
68+
```
69+
70+
### 레이아웃
71+
72+
Next.js에서 `layout.tsx` 파일은 여러 페이지에 걸쳐 공통된 UI를 정의하는 역할을 한다. 이름 그대로 웹사이트의 '뼈대'나 '틀'을 만드는 파일이라고 생각하면 쉽다.
73+
74+
app 디렉토리 안에 layout.tsx를 만들면 그 안에 포함된 모든 페이지(하위 폴더 포함)에 해당 레이아웃이 자동으로 적용됩니다.
75+
76+
## API Route Handler
77+
78+
- Next.js의 서버 라우트를 활용하기 위해서는 원하는 주소 안에 `route.ts` 파일을 만들고 정의해주면 된다.
79+
- 대체로 `api/`폴더를 만들고 그 안에 원하는 경로 대로 폴더를 만든 이후 `route.ts`파일을 생성한다.
80+
- Express.js와 유사하게 요청(request)과 응답(response) 객체를 다루며, 다양한 HTTP 메서드(GET, POST, PUT, DELETE 등)를 자유롭게 처리할 수 있다.
81+
82+
```tsx
83+
import { NextResponse } from "next/server";
84+
85+
export async function GET(request) {
86+
return NextResponse.json({ message: "Hello, World!" });
87+
}
88+
```
89+
90+
## ServerAction
91+
92+
- React18에 도입된 기능으로 클라이언트 컴포넌트나 서버 겈모넌트 내에서 서버 코드를 직접 시행할 수 있게 해준다.
93+
- 함수에 `'use server'`지시어를 추가하여 정의하며, 주로 폼(form) 제출이나 데이터 변경(mutaion) 작업에 사용된다.
94+
95+
```tsx
96+
export default function MyComponent() {
97+
async function createInvoice(formData) {
98+
"use server";
99+
100+
const rawFormData = {
101+
customerId: formData.get("customerId"),
102+
amount: formData.get("amount"),
103+
status: formData.get("status"),
104+
};
105+
106+
// 데이터베이스에 데이터 저장 로직
107+
// ...
108+
109+
revalidatePath("/dashboard/invoices"); // 관련 페이지 캐시 갱신
110+
}
111+
112+
return (
113+
<form action={createInvoice}>
114+
{/* 폼 입력 필드들 */}
115+
<button type="submit">Create Invoice</button>
116+
</form>
117+
);
118+
}
119+
```
120+
121+
- ServerAction은 Server component 안에서만 정의되고 사용될 수 있다. 따라서 client component를 사용할 때에는 다른 파일로 빼서 주입시켜 주어야 한다.
122+
123+
### 주요 특징
124+
125+
- 컴포넌트와 결합된 로직: UI와 관련된 서버 로직(예: 폼 데이터 처리, 데이터베이스 업데이트)을 해당 컴포넌트 파일 내에 함께 작성하여 개발 경험을 간소화한다.
126+
127+
- 별도의 API 엔드포인트 불필요: API 라우트를 따로 만들 필요 없이 함수 호출만으로 서버 로직을 실행할 수 있다.
128+
129+
- 데이터 변경에 최적화: revalidatePath, revalidateTag와 같은 기능을 통해 데이터 변경 후 관련된 페이지나 데이터 캐시를 손쉽게 갱신할 수 있다.
130+
131+
- 보안: 내장된 CSRF 보호 기능을 제공한다. 기본적으로 POST 요청으로 처리된다.
132+
133+
### useFormStatus hook
134+
135+
React에서 기본적으로 제공하는 훅 중에 `useFormStatus`라는 훅이 존재한다.
136+
ServerAction 자체가 formData를 전송하는것에 주로 사용되다 보니 궁합이 잘맞는 훅이다.
137+
client component 에서 사용이 가능하며 form 태그 안에 존재해야 한다.(해당 hook은 부모 컴포넌트들을 찾아보고 가장 가까운 form을 찾는다.)
138+
139+
> [!info]
140+
>
141+
> `'use client'`는 컴포넌트가 동적이어야 할때 작성해 주어야 한다.
142+
> `'use client'`를 사용하면 `inline server action`을 사용할 수 없다.
143+
144+
해당 훅은 다음과 같은 상태를 알려준다.
145+
146+
- action: 현제 실행중인 서버액션 함수
147+
- pending: 실행중인지 여부
148+
- method: http메소드
149+
- data: 제출된 formData
150+
151+
```tsx
152+
"use client";
153+
154+
import { useFormStatus } from "react-dom";
155+
156+
export default function FormBtn({ text }: FormBtnProps) {
157+
const { pending } = useFormStatus();
158+
return (
159+
<button
160+
disabled={pending}
161+
className="primary-btn
162+
h-10
163+
disabled:bg-neutral-500
164+
disabled:text-neutral-300
165+
disabled:cursor-not-allowed
166+
"
167+
>
168+
{pending ? "로딩 중..." : text}
169+
</button>
170+
);
171+
}
172+
```
173+
174+
### useFormState hook
175+
176+
결과를 ui로 전달하는 역할
177+
서버액션의 결과 특히 오류 등을 가져올 수 있는 역할을 한다.
178+
179+
useFormState 훅은 인자로 action함수와 초기값을 받으며 클라이언트 컴포넌트에서 사용 가능하다.
180+
181+
ServerAction 의 경우 서버 컴포넌트에서 사용 가능하기 때문에 다른 파일로 따로 분리한 이후 불러와 사용해야 한다.
182+
183+
```tsx
184+
"use client";
185+
import FormBtn from "@/components/form-btn";
186+
import FormInput from "@/components/form-input";
187+
import SocialLogin from "@/components/social-login";
188+
import { useFormState } from "react-dom";
189+
import { handleForm } from "./actions";
190+
191+
export default function Login() {
192+
const [state, action] = useFormState(handleForm, null);
193+
194+
return (
195+
<div className="flex flex-col gap-10 py-8 px-6">
196+
<div className="flex flex-col gap-2 *:font-medium">
197+
<h1 className="text-2xl">안녕하세요!</h1>
198+
<h2 className="text-xl">Log in with email and password.</h2>
199+
</div>
200+
<form action={action} className="flex flex-col gap-3">
201+
<FormInput
202+
name="email"
203+
type="email"
204+
placeholder="Email"
205+
required
206+
errors={[]}
207+
/>
208+
<FormInput
209+
name="password"
210+
type="password"
211+
placeholder="Password"
212+
required
213+
errors={[]}
214+
/>
215+
216+
<FormBtn text="Log In" />
217+
</form>
218+
<SocialLogin />
219+
</div>
220+
);
221+
}
222+
```
223+
224+
## API Route Handler vs ServerAction

content/posts/프로젝트/당근마켓 클론코딩/당근마켓 클론코딩으로 기본적인 tailwind 복습하기.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ tags:
33
- project
44
- carrot-market
55
- study
6-
- clone
76
- tailwind
87
createdAt: 2025-06-14 15:04:37
9-
modifiedAt: 2025-06-29 15:46:52
8+
modifiedAt: 2025-06-30 08:56:48
109
publish: 프로젝트/당근마켓 클론코딩
1110
related: ""
1211
series: ""

public/link-map.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"2.area/블로그/Archive로 이동시킨 노트들을 블로그에 포스팅할때 문제.md": "영역/블로그/Archive로 이동시킨 노트들을 블로그에 포스팅할때 문제",
5050
"2.area/개발/내가 1년간의 리눅스 개발 여정을 끝내고 윈도우와 맥으로 돌아온 이유.md": "영역/개발/내가 1년간의 리눅스 개발 여정을 끝내고 윈도우와 맥으로 돌아온 이유",
5151
"1.project/당근마켓 클론코딩/당근마켓 클론코딩으로 기본적인 tailwind 복습하기.md": "프로젝트/당근마켓 클론코딩/당근마켓 클론코딩으로 기본적인 tailwind 복습하기",
52+
"1.project/당근마켓 클론코딩/당근마켓 클론코딩으로 기본적인 Next.js 복습하기.md": "프로젝트/당근마켓 클론코딩/당근마켓 클론코딩으로 기본적인 Next.js 복습하기",
5253
"1.project/당근마켓 클론코딩/당근마켓 클론코딩.md": "프로젝트/당근마켓 클론코딩/당근마켓 클론코딩",
5354
"1.project/괴담집/괴담집 프로젝트 소개.md": "프로젝트/괴담집/괴담집 프로젝트 소개",
5455
"1.project/괴담집/괴담집 이야기 생성 워크플로우 구축.md": "프로젝트/괴담집/괴담집 이야기 생성 워크플로우 구축",

public/meta-data.json

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@
282282
"tags": ["resource", "linux", "onedrive", "wsl"],
283283
"series": "",
284284
"createdAt": "2025-06-07 13:01:39",
285-
"modifiedAt": "2025-06-12 16:34:24",
285+
"modifiedAt": "2025-06-30 09:27:08",
286286
"publish": "자원/Linux"
287287
},
288288
{
@@ -535,18 +535,29 @@
535535
"tags": ["area", "\uac1c\ubc1c"],
536536
"series": "",
537537
"createdAt": "2025-06-14 18:33:27",
538-
"modifiedAt": "2025-06-14 19:17:57",
538+
"modifiedAt": "2025-06-30 08:59:46",
539539
"publish": "영역/개발"
540540
},
541541
{
542542
"urlPath": "프로젝트/당근마켓 클론코딩/당근마켓 클론코딩으로 기본적인 tailwind 복습하기",
543543
"title": "당근마켓 클론코딩으로 기본적인 tailwind 복습하기",
544544
"summary": "",
545545
"image": "",
546-
"tags": ["project", "carrot-market", "study", "clone", "tailwind"],
546+
"tags": ["project", "carrot-market", "study", "tailwind"],
547547
"series": "",
548548
"createdAt": "2025-06-14 15:04:37",
549-
"modifiedAt": "2025-06-29 15:46:52",
549+
"modifiedAt": "2025-06-30 08:56:48",
550+
"publish": "프로젝트/당근마켓 클론코딩"
551+
},
552+
{
553+
"urlPath": "프로젝트/당근마켓 클론코딩/당근마켓 클론코딩으로 기본적인 Next.js 복습하기",
554+
"title": "당근마켓 클론코딩으로 기본적인 Next.js 복습하기",
555+
"summary": "",
556+
"image": "",
557+
"tags": ["project", "carrot-market", "study"],
558+
"series": "",
559+
"createdAt": "2025-06-30 08:48:51",
560+
"modifiedAt": "2025-06-30 21:16:46",
550561
"publish": "프로젝트/당근마켓 클론코딩"
551562
},
552563
{
@@ -557,7 +568,7 @@
557568
"tags": ["project", "carrot-market", "study", "clone"],
558569
"series": "",
559570
"createdAt": "2025-06-13 11:29:34",
560-
"modifiedAt": "2025-06-17 22:24:43",
571+
"modifiedAt": "2025-06-30 15:17:53",
561572
"publish": "프로젝트/당근마켓 클론코딩"
562573
},
563574
{
@@ -612,7 +623,7 @@
612623
"tags": ["project", "\ud68c\uace0", "portfolio", "archive"],
613624
"series": "",
614625
"createdAt": "2025-03-25 16:46:50",
615-
"modifiedAt": "2025-06-17 14:31:02",
626+
"modifiedAt": "2025-06-30 13:18:05",
616627
"publish": "프로젝트/아임유어박스 웹사이트"
617628
},
618629
{

0 commit comments

Comments
 (0)