~ 2024.6.1

CSR은 클라이언트가 브라우저 렌더링을 처리하는 방식으로, 클라이언트가 화면을 그리는 주체이다.
서버는 페이지 접근 요청이 오면 HTML, JS파일을 전달만하고 브라우저가 이것을 받아 JS파일을 실행하면서 DOM에 내용을 추가하고 리액트를 실행하여 화면을 렌더링 한다.
위 이미지를 보면 알 수 있지만 리액트의 실행이 완료되기까지 브라우저는 계속해서 loading상태이다.

즉, 누가 봐도 무슨 페이지인지 알 수 없는 이 상태를 브라우저는 계속 유지하고 있고 웹사이트를 분석하여 검색하는 프로그램인 검색엔진의 입장에서도 해당 웹사이트의 정보를 알 수 없다. 검색엔진은 HTML만 들여다 보기 때문이다. (크롤링 할 수 없다고 표현한다.)
→ 결론적으로 CSR은 SearchEngineOptimization ( 검색 엔진 최적화, 검색엔진에 친화적인 사이트를 구축하여 광고가 아닌 자연 검색을 통해서 트래픽의 양과 질을 극대화 하는 작업 )에 불리하다.
아무리 좋은 웹사이트를 만들어도 사람들에게 노출되지 않고 누구도 이용하지 않으면 의미가 없다.

SSR에서 화면을 그리는 주체는 서버이다. 클라이언트가 서버에 데이터를 요청하면 매번 서버에서 새로운 View화면을 생성하여 제공한다.
서버에서는 이미 작성되어있는 HTML과 그것을 동적으로 제어 할 수 있는 JS코드를 클라이언트에게 제공하고, HTML이 이미 작성되어 있기 때문에 브라우저에는 바로 렌더링된다.
여기에 차차 js코드와 리액트가 실행되고 완료되면 사용자는 브라우저와 상호작용을 할 수 있게 된다.
이렇게 SSR에서는 서버와 통신이 끝난 시점부터 HTML에 해당 페이지의 정보가 작성되어 있기 때문에 검색엔진이 크롤링을 할 수 있게되고 SEO가 향상된다.
이렇게 해서 Next.js는 SSR을 통해서 SEO도 증가시키고, SPA를 사용하여 UX도 향상 시킬 수 있다.
📌 즉, Next.js를 이용하면 CSR과 SSR의 장점을 모두 활용하여 사용 할 수 있다.
+) 라이브강의에서 들은 내용 추가 : HTML을 서버에서 만들어서 제공하고, 해당 페이지에 자바스크립트가 필요하면 자바스크립트도 제공한다. 만약 아닌경우에는 HTML만 제공하기도 한다.
+) Next.js는 Full-Stack이다. next.js만으로도 서버를 만들 수 있다는 의미이다. 개발환경이 통합되어서 개발 속도가 향상되고, 클라이언트와 서버를 따로 배포를 하지 않아도 되기 때문에 CORS설정을 하지 않아도 된다.
+) 또 다른 특징은 프레임워크라는거다. 리액트는 UI를 만드는데 특화되어있는 라이브러리였다면 next.js는 전반적인 기능을 모두 제공하는 프레임 워크다. 개발에 필요한 대부분의 기능이 갖춰져있기 때문에 dom이나 상태관리를 위해 리액트처럼 라이브러리를 설치하거나 일일이 설정할 필요가 줄어든다. (없지는 않다.) 자체적으로 기능을 가지고 있다는 것은 라이브러리나 모듈의 호환성으로 인한 문제가 줄어들게 된다는 것이다. (싱크가 잘 맞다.)
+) 강의 중 성현님의 질문 
어느 정도는 맞는 말일수도 있다. 리액트 공식 홈페이지에서도 보면 리액트 기반의 프레임워크를 사용할 것을 권장하고 있다.
next.js는 페이지를 pre-render한다. 모든 페이지를 위한 HTML을 Client사이드에서 자바스크립트로 처리하기 전에 ‘사전에’ 생성한다는 의미이다.
이것을 확인해보려면 웹페이지에서 javascript disable설정을 해보면 된다.
→ 사용 방법 : https://developer.chrome.com/docs/devtools/javascript/disable?hl=ko
리액트 샘플 사이트 ( https://create-react-app.examples.vercel.com/ ) 에 접속해서 javascript disable을 적용하면

이렇게 화면이 렌더링 되지 않는다. 현재 애플리케이션이 CSR을 하기 때문에 자바스크립트가 동작하지 않으면 화면을 그릴 수 없게 되는 것이다.
next.js 샘플사이트 ( https://next-learn-starter.vercel.app/ ) 에 접속해서 똑같이 javascript disable을 적용하면

source에 경고등이 켜져있는걸로 js disable이 적용되어있는걸 확인 할 수 있는데도 화면이 렌더링 되어있다.
이상태로 링크로 이동하는 등의 동적인 상호작용은 불가능하지만 자바스크립트가 꺼져있는데도 화면이 떠있다는것이 해당 페이지가 pre-render하고 있다는 증거이다.
다시 정리하면 next.js에서는 브라우저를 렌더링 할 때 pre-rendering을 한다. HTML DOM 요소를 build해서 HTML문서를 렌더링하고 거기에 리액트 컴포넌트가 초기화되면서 상호작용을 할 수 있게 된다. 그리고 요청이 올 때마다 JS로 이벤트를 동작시킨다.
이렇게 렌더링된 HTML에 리액트가 실행되는 것을 Hydration이라고 한다. 딱딱하고 정적인 문서에 촉촉하게 이벤트를 추가한다는(ㅋㅋ) 느낌이다.
next.js의 렌더링 방식인 pre-render가 어떤 과정에 의해 실행되는가에 따라서 SSR과 SSG가 나뉘어진다.
매 요청마다 HTML파일을 만들고 렌더링 하는 과정은 불필요하게 서버의 자원을 낭비하게 됨으로, 렌더링 시점을 클라이언트가 요청을 받았을 때가 아니라 페이지를 처음 빌드 할 때로 변경하는 것이다.
미리 HTML을 만들어두고 이것을 사용자에게 보여주는것이 SSG 방식이다. pre-render된 페이지를 보여준다는 것은 SSR과 동일하지만 미리 렌더링 해두는 것이기 때문에 변경사항을 업데이트 할 수는 없지만 CSR, SSR에 비해서 렌더링 속도가 빠르고 서버 부하가 줄어든다. ( 만들어둔걸 제공만 하면 되니까 )
Next에서는 두가지 중 선택 할 수 있으면 SSG를 사용하는것을 권장하고 있다.
이렇게 SSR이냐 SSG이냐에 따라서 Next.js에서 data fetching하는 방식이 달라지게 된다.
data fetching은 데이터 소스에서 데이터를 가져오는 과정을 말한다. next.js에서는 SSR과 SSG 중에서 어떻게 데이터를 가져올 것인가에 따라서 다른 메소드를 사용한다.
SSR data fetching : getServerSideProps()
export async function getServerSideProps(context){
return {
props : {}
}
}
해당 메서드로 요청이 오면 next.js는 각 요청마다 리턴되는 데이터를 pre-render한다.
서버가 모든 요청에 대한 결과를 계산하고 CDN에 의해 결과를 캐시 할 수 없기 때문에 SSG에 비해서 느리다.
SSG data fetching :
export async function getStaticProps(context){
return {
props : {}
}
}

getStaticProps는 클라이언트측이 아닌 서버 측에서 실행되어 build시에 딱 한번 호출되면서 static file을 생성한다. API와 같은 외부데이터를 받아서 static generation 한다.
→ 서버로 데이터를 요청하여 받아서 페이지를 생성 할 때, build시 서버측에서 처음 한번만 해당 함수를 실행하여 요청받은 페이지를 pre-render한다는 소리다.
위 코드에서는 그렇게 받아온 data를 기반으로 About 페이지의 게시글 목록을 생성하고 있다.
이렇게 큰 변화가 없이 나열해야 하는 정보들을 받아 올 때 주로 사용한다.
getStaticPaths() : 동적 경로에 대해 미리 렌더링 할 페이지의 경로 목록을 정의하는 함수이다.
→ 쉽게 말하면 어떤 경로를 pre-render할지 정한다.
pages/detail-static/[id].js 와 같이 Next.js에서 동적 경로는 파일명에 대괄호를 붙여서 정의한다. 앞에서 게시글 목록을 생성한다고 예를 들었는데 거기에서 게시글을 하나씩 눌러서 해당 게시글의 상세페이지를 봐야하는 상황에서 게시글의 id를 넣어서 동적으로 페이지를 생성한다. import React from "react";
import axios from "axios";
const DetailStatic = ({ item }:any) => {
return (
<div>
{item && (
<div className="Detail">
<h1 style={{ color: "#fff" }}>with Static Generation</h1>
<h1>{item.title}</h1>
<p>{item.body}</p>
<p>{item.id}번째 게시글</p>
</div>
)}
</div>
);
};
export default DetailStatic;
export const getStaticPaths = async () => {
console.log("path")
return {
paths: [
{ params: { id: "1" } },
{ params: { id: "2" } },
{ params: { id: "3" } },
],
fallback: true,
};
};
export const getStaticProps = async (ctx:any) => {
console.log("props")
const id = ctx.params.id;
const res = await axios.get(
`https://jsonplaceholder.typicode.com/posts/${id}`
);
const data = res.data;
return {
props: {
item: data,
},
};
};
예를들어 이런 코드가 있다.
실행 순서는 getStaticPaths -> getStaticProps -> DetailStatic이다.
해당 파일명은 [id].js 였을 것이다. (아마도) 그것이 params가 되기 때문에 getStaticPaths함수에서 path에 id를 적는다.
id 1, 2, 3에 해당하는 경로는 build시에 pre-render하여 생성한다고 getStaticPaths에 지정하면,
getStaticProps가 return값을 받아서 params를 읽고 해당 게시글을 pre-render하고 미리 생성해둔다. ( 결국에 생성하는 거는 항상 getStaticProps다.)
그러면 해당 컴포넌트는 다시 그 결과값을 받아서 화면을 그리기만 하면 된다.
fallback은 path에 등록되어 있지 않은 경로에 접근 했을 때 어떻게 처리할거냐를 정한다. false이면 404로 처리하고, true이면 서버에서 작성한대로 처리한다.
이렇게 라우터를 처리 할 때 getStaticProps로 리턴되지 않는 경로에 접근하려고 하면 어떤 페이지를 보여줄지 결정 할 수 있다.

위 코드가 처리되면 이렇게 파일이 정적으로 미리 생성되어있다. 어떤 게시판의 공지글 같은것이 예시가 될 수 있다. 디테일한 페이지 이면서도 변경할 사항이 크게 없다.
만약 1번 페이지에 접근하면 바로 내용이 채워진 페이지가 로딩될거고, 5번 페이지에 접근하면 페이지가 로딩 된 후에 내용이 채워지게 될것이다. 1~3번 페이지만 pre-render해뒀기 때문이다
Next.js에서는 라우터를 별도로 설치하지 않고 파일 기반 라우팅을 지원한다. 설정된 폴더 구조로 부터 폴더명, 파일명에 따라서 자동으로 Path를 도출해 설정한다. 동적 라우팅의 경우 파일명, 폴더명을 [ ] 로 감싸준다

생성된 rotuer객체에 접근하려면 useRouter()훅을 사용하면 된다. push하면 받은 url로 이동한다.
import { useRouter } from "next/router";
export default function Home() {
const router = useRouter();
router.push(url, as, options);
}

npx create-next-app@latest를 하고 나면 생성되는 폴더 구조이다.
원하는 대로 설정을 해서 만들면 된다.
App Router는 위에서 공부했지만, 최신 버전 next.js에서 제공하는 Router방식이다. 그것을 사용할것이냐고 묻는거고
alias는 여기 블로그와 여기 블로그를 보면 상대경로를 사용하고 그걸 커스텀 할것인지, 아니면 절대 경로를 사용하는지를 결정하라는 것 같다.
styles폴더를 보면 Home.module.css파일이 있다. next.js에서는 이렇게 css를 적용한다. home은 index.tsx를 가리킨다. 해당하는 컴포넌트에 종속적인 css파일을 만들고 싶은 경우 module을 붙인다.
pages폴더안에 생성하고자 하는 페이지들을 생성한다. index.tsx가 /로 첫 경로가 된다.
public 폴더는 이밎와 같은 정적 에셋을 보관한다.
next.config.js 는 next.js가 웹팩을 기본 번들러로 사용하기 때문에 웹팩에 대한 설정을 이 파일에서 할 수 있다.
tsconfig.json은 해당 애플리케이션을 만들 때 typescript를 사용하겠다고 해서 만들어진 파일이다. ts를 관리하면 된다.
next.js 12 버전까지는 page router방식만 있었는데, 13버전이 되면서 app router 방식을 도입했다.
차이는 위와 같다. 하나씩 살펴보자.
12에서는 pages 폴더 안에 여러 파일을 만들고, /경로는 index.js파일을 보여주는 방식이었다.
13버전에서는 pages폴더가 없고 app폴더를 사용하고 pages.js로 바뀌었다.
처음 create-next-app 해서 설치 할 때
No를 선택하면 page router를 위한 구조로 설치가 되고 Yes를 선택하면 App router를 위한 구조로 설치가 된다.
12버전에서는 이렇게 pages에 파일을 만들면 그것이 경로가 된다.
13버전에서는 경로명에 해당하는 폴더를 app 폴더 내에 만들고 내부에 page.js파일을 만들면 해당 경로로 이동한다.
위에서 언급했던 layout을 담당하는게 _app.js라는것도 12버전의 설명이다. 13버전에서는 layout.js파일이 레이아웃을 담당한다.
api폴더 서버를 열 수 있다는 점은 동일하다.
다만 13버전에서는 api폴더를 기본으로 생성해주지는 않고 만들어서 사용하면 된다.
다만 13버전에서 페이지를 만드는 것과 같이 해당하는 경로명으로 폴더명을 만든 후 route.js로 만들면 된다.
즉, 13버전에서는 page명은 다 폴더명으로 만들고 내부에 page.js로 작성하면 되고 / api도 마찬가지로 폴더명으로 url경로를 만들고 route.js로 파일을 작성하면 된다.
다만 api를 작성하는 방법이 13버전에서는 달라진다. 요청 메소드를 함수명으로하고, Nextresponse, Nextrequest등 정해진 방법대로 작성해야한다.
가장! 큰! 차이점은! 아까 위에서 getStatic 어쩌구저쩌구 한것들을 13버전에서는 사용하지않아도 된다!!
next.js도 결국 리액트 기반이라서 getStatic어쩌구 함수들을 사용하지 않고, 리액트에서 일반적으로 사용했던 것처럼 useEffect와 fetch or axios를 사용하여 데이터 통신을하고, 그것들을 CSR방식으로 사용해서 컴포넌트를 업데이트 할 수 있다.
그러다가 필요한경우에 getStatic어쩌구 함수들을 이용하면 SSR이나 SSG로 페이지를 제공 할 수 있었다.
결론적으로 next.js에서는 이렇게 필요에 따라서 선택해서 페이지를 렌더링 했다.
이걸 next13버전에서는 Server Component, Client Component라는 개념을 도입했다.
아주 간단하다.
컴포넌트 맨 윗줄에 이렇게 use client라고 작성하면 client component이다. 그러면 리액트에서 했던것처럼 CSR을 제공하는 컴포넌트가 된다.
해당 문장이 없으면 일반적으로 모드 server component로 취급한다. 그리고
원래 기본 자바스크립트에서 통신 했던것처럼 데이터 통신을 하면 된다.
이러한 개념이 가능한것은 React18에서 컴포넌트를 Client Component와 Server Component를 분리했기 때문이라고 한다.
그러면 ssg나 ssr은 어떻게 사용하는가?
next13의 기본컴포넌트가 된 server component에서는 getStatic어쩌구 메서드를 사용할 수 없다. 대신에 기본 API인 fetch()를 확장하여 cache, next 옵션으로 ssr, ssg를 구분할 수 있다.
const fetchData = async () => {
const res = await fetch('https://api.example.com/data', { cache: 'no-store' });
return res.json();
};
cache : no-store 옵션을 통신에 추가하면 SSR로 동작한다. 캐싱작업을 하지 않고 새로운 요청이 있을 때마다 매번 데이터를 불러오게 설정한다.
const fetchData = async () => {
const res = await fetch('https://api.example.com/data', { cache: 'force-cache' });
return res.json();
};
cache : force-cache옵션을 추하면 SSG로 동작한다. 이것이 default-value라고 한다. 즉 서버컴포넌트는 기본적으로 ssg로 동작하게 되었다. 처음에는 server-side에서 작동하고 두 번째 부터는 캐싱된 값을 불러온다.
ssg방식을 사용하면서 주기적으로 데이터를 불러오기 위해서 (ISR)는
const fetchData = async () => {
const response = await fetch('https://api.example.com/data', {
next: {
revalidate: 10,
},
});
return res.json();
};
{next: {revalidate: minute}} 옵션을 주면 된다. 지정된 시간 간격으로 페이지를 다시 생성하여 최신 데이터를 반영한다. 별도의 빌드 과정 없이 해당 데이터를 볼 수 있다고 한다.
서버컴포넌트와 클라이언트 컴포넌트를 사용해야하는 상황별 표
<Image> 컴포넌트
next.js에서 이미지를 삽입하고자 할 때 그냥 <img/>태그를 사용해도 되지만 ( next.js에서는 꼭 닫는 태그를 사용해야 한다. ), 외부에서 불러오는 이미지의 경우에는 next.js에서 제공하는 <Image>컴포넌트를 사용하면 최적화에 도움이 된다.
lazy loading & 사이즈 최적화 & layout shift를 방지한다고한다.
lazy loading : 이미지 로드 하는 시점을 필요 할 때까지 지연시키는 기술을 말한다. 필요한 이미지만 빠르게 로드 할 수 있도록 할 수 있다. 보통 scroll 이벤트를 통해 스크린에 element가 보일 때를 캐치하여 이미지를 로드하도록 구현하고 img태그에 loading='lazy' 소성을 추가하여 간단하게 적용 할 수 있다.
<Image>컴포넌트를 사용하면 자동으로 적용이 된다. lazy load를 끄고싶은 경우에는 priority prop을 true로 설정하면 된다.
만약 현재 페이지에 불러와야 하는 이미지가 약 50개라면, 우선적으로 보여줄 이미지를 선택해서 먼저 로딩되게 할 수 있는 것이다.
사이즈 최적화 : 솔직히 읽어도 무슨말인지 완전히 이해는 못했다. 이미지가 할당된 위치의 공간에 맞게 이미지의 사이즈를 만들어주고 그래서 용량도 줄일 수 있다는 것 같다.
placeholder : 웹사이트의 구성요소들이 순서대로 로드되다보면 눈으로 볼 때 영역이 막 움직이고 이동하는것 처럼 느껴 질 수 있다. 레이아웃이 흔들리게 된다. 이것을 CLS(custom layout shift)라고 부르는데, 이것을 방지해준다. 이미지가 로드되기 전에도 이미 이미지 높이만큼 영역을 표시해서 이미지가 로드되고 나서도 레이아웃이 유지된다.
로컬 이미지의 경우 자동으로 width, height를 지정하고 blur 이미지를 생성한다.
리모트 이미지의 경우
어떤 url에서 접근하는 이미지인지를 명시해야하고, 첫 <Image>컴포넌트 예시처럼 width, height를 명시해야한다. (위 예제에서는 일단 0으로하고, style로 추가 적용 했다. 아마도 px만 사용할 수 있기 때문인 것 같다.) 빌드타임에 이미지파일에 접근하는것이 불가능 하기 때문이다. ( 외부파일이니까 ) blur이미지도 생성되지 않기 때문에 별도로 속성을 줘야한다.
예시에서 사용된 sizes속성은 뷰포트 너비에 따라 이미지 크기를 어떻게 조정할지를 알려주는 역할을 한다. (실제로 사용해보면, 내가 반응형을 적용하지 않았는데도 웹 페이지 사이즈를 줄여보면 반응형처럼 이미지가 조정된다.)
next.js에서 제공하는 것 중에 하나로 로딩 UI를 만드는데 도움이 된다. 컨텐츠가 로드되는 동안 서버에서 즉시 보여줄 컨텐츠를 만들 수 있으며 로딩이 끝나면 작성한 컨텐츠로 대체된다.
현재 페이지 컴포넌트에서 오류가 발생했을 때 가장 가까이에 있는 error.js를 실행하여 레이아웃 내에서 표시되게 할 수 있다. https://nextjs.org/docs/app/building-your-application/routing/error-handling 에서 추천하는대로 error.js파일을 생성하고 일부러 에러를 발생시켜보면
이렇게 나타난다.
next/navigation에서 import해온 useRouter에서 제공한다. refresh()를 호출하면 서버에서 업데이트된 데이터를 새로고침하여 가져온다. 
예를 들어 위와 같은 상황이 있다. 게시글을 버튼을 눌러서 추가하는데 기본적으로 server component이다보니 변경사항을 바로 적용하지 않는다. 추가후에 새로고침버튼을 일부러 눌러야 적용이 된다. 그런데 보통 이렇게 동작하기를 원하지 않는다. 이떄 사용하는게 refresh이다.
통신이 끝난 후에 refresh()를 사용하면 화면은 진짜 새로고침을 하는것처럼 (ㅋㅋ) 깜빡이지 않는데도 데이터를 새로 받아와서 화면에 그려준다.
'next/nagivation' 과 'next/router'의 차이는 전자는 13버전 이상에서 RSC React Server Component를 사용하는 경우에 useRouter()를 사용 할 때 이고, 후자는 12버전 이하 = RSC를 사용하지 않는 경우 = client side routing에서 주로 사용한다.
(확실하지않음)
db에 어떤 데이터를 요청하려면 원래 server를 통해서 해야함.
그래서 맨 처음에 했던 실습을 보면 이렇게 서버 역할을 하는 api폴더에 해당하는 경로에
요청을 보내고
거기서 이렇게 처리를 해야 했다. 이게 next12버전에서 사용한거다. (참고로 getStatic어쩌구는 내부에서 직접 db를 연결하더라 아마 이미 서버컴포넌트로 동작하고 있어서 가능 한 것 같다.)
그런데 next13에서는 첨 시작하면 api폴더도 따로 안만들어준다.(만들어도된다.)
왜냐면 기본이 server component이기 때문에 서버로 동작한다.
그래서 몇가지 설정만해주면 위에처럼 server경로로 이동하고 하는 과정 없이(api를 만들 필요 없이) 바로 현재 작성중인 컴포넌트에서 db로 요청을 보낼 수 있다.
그게 server action기능이다. (아마도)
이 기능을 사용하려면
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverActions: true,
},
};
export default nextConfig;
next.config.mjs에 위와 같이 true를 입력해줘야한다.
서버액션은 사용하는 컴포넌트 아무데서나 사용 할 수 있다. (심지어 클라이언트 컴포넌트에서도 사용법만 달라질 뿐 사용 할 수 있다.)
매우 간단하다 함수 위에 'use server'를 입력해주면 된다. ( 이게 다는 아니다. )
import Image from "next/image";
export default function Component() {
async function myAction() {
'use server';
}
return (
<div></div>
);
}
컴포넌트 내부의 myAction함수는 이제 서버액션으로 동작한다. 이것은 서버컴포넌트에서 사용하는 방법이다.
클라이언트 컴포넌트에서 사용하려면 

이렇게 form에 action이라는 속성을 주고 사용하면 된다.
클라이언트 컴포넌트에서 form의 action props는 서버액션을 부를 수 (invoke)있게 해준다.

사용법은 위와같다. 'use server'라고 적어놓으면 되고, 이때까지 한 것 처럼 요청을 보내면 된다.
눈여겨볼점은 data.get('title')이 모냐는거다. 이게 모냐면 form에서 action={addtodo}이렇게 하고있으면 form내부의 정보를 addtodo로 전달? 을 해준다. 위에서는 form내부의 input중에 name이 title인 태그의 value를 get메소드를 사용해서 title에 저장하고 있는거다.
또 revalidatePath는 뭐냐면 이게 CSR이 아니다 보니 뭘 추가해도 화면이 바로 안바뀌는데 그것은 현재 화면이 캐시되어 있기 때문이다. revalidatePath를 사용하면 지금 받은 값으로 새롭게 캐시를 해준다.(캐시를 해주는거니까 refresh랑은 다르다.)
서버액션의 큰 특징은 progressive enhancement이다.
progressive enhancement라는것의 원래 뜻은 기본적인 기능과 콘텐츠는 모든 사용자와 브라우저에서 접근 가능하게 제공하고, 추가적인 기능과 향상된 경험은 더 현대적인 브라우저와 기기에서만 사용할 수 있도록 하는 접근법이라고 하는데.
강의에서 설명한걸로는
서버액션을 사용하면 js없이도 = js를 disable해도 기본적으로 동작한다는 것이다.
source를 보면 js가 꺼져있는걸 볼 수 있다. 그런데도 제출을 누르면 투두가 잘 추가된다.
즉, 자바스크립트 없이도 기본적으로 제공되어야 하는 기능들을 사용 할 수 있게 해준다는 것 같다.
form태그에서 server action을 사용 할 때는 action props를 사용했다면, form태그 내부의 input이나 button이 server action을 사용 할 때는 formAction을 사용해야 한다.
그리고 그 내부에서 똑같이 'use server'해주면된다.
그리고 서버액션은 모두 async를 사용해야한다. (비동기로 해주야한다!)
action이나 formAction없이 서버액션을 사용하는 마지막 방법은 startTransition이다.
const Checkbox = ({todo}: {todo: Todo}) => {
const [isPending, startTransition] = useTransition();
return (
<input
className="min-w-[1.5rem] min-h-[1.5rem]"
type="checkbox"
checked={todo.completed}
id="completed"
name="completed"
disabled={isPending}
onChange={() =>
startTransition(() => {
updateTodo(todo);
})
}></input>
);
};
export default Checkbox;
startTransition은 비동기작업을 시작해주고, isPending은 비동기 작업이 실행중일 때는 true가 되고 끝나면 아니면 false가 된다.
위 코드는 disabled에 isPending을 줬다. 즉, 비동기통신이 진행 되는 중에는 disabled=ture가 되어서 체크박스를 사용 하지 못하도록 하고, 끝나면 disabled=false가 되어서 다시 사용 할 수 있게 한다.
그리고 체크박스를 눌러서 onChange가 일어나면
통신을 하게 된다.
sleep이라는 함수로 일부러 지연을 주게 만들면
이렇게 체크박스를 한번 누르면 통신이 끝나고 함수가 끝나는 2초동안에 체크박스가 회색이 되어서 사용 할 수 없는 모습을 볼 수 있다.
(정확하지않다) 내가 이해한걸로는, (설명을 안해주셨다) todo를 받아서 그걸 기반으로 새로운 객체로 만들고 그걸로 optimisticTodo라는 상태를 만든다.onChange가 일어나면 todo를 바꾸고 있는데, optimisticTodo도 todo를 기반으로 만들어지고 있기 때문에 변하게 된다. 그리고 그걸 사용해서 checked 여부를 보여주고 있으니까 통신의 끝 여부와 상관없이 일단 화면이 업데이트 된다.
즉 UI는 통신의 완료 여부와 상관없이 일단 업데이트 되어있고 통신은 따로 돌아가고 있는거다. 실제로 updatetodo 내부에는 아직 아까 줬던 sleep함수가 들어있는데도 체크박스를 누르면 ui에 바로 반영되더라.
그리고 터미널에서 ./pocketbase serve를 입력하면
내 컴퓨터의 포트 중 한곳에서 서버를 열어준다.
admin UI를 눌러서 보면 이렇게 ui로 확인 할 수 도 있다. 요청은 REST API로 보내면 된다.new collection -> 이름입력 -> 실습에서는 텍스트만 보낼거라 플레인텍스트 선택 -> api rules 모두 잠금 -> save
new record를 눌러서 임의로 추가해줬다. title만 입력해도 해당 시점의 시간과 id를 자동으로 생성해준다. 이렇게 db의 역할도 하고있다.
async function getPosts() {
const res = await fetch(
"http://127.0.0.1:8090/api/collections/posts/records"
);
const data = await res.json();
return data?.items as any[];
}
이런식으로 요청을 보내고 받아 올 수 있다.


포켓베이스와 비슷하게 서버를 열어주고 거기에 JSON을 전송하면 db에 저장해준다. 위에서는 명시적으로 3001번 포트에 서버를 열고 기본적으로 사용할 db데이터파일을 만들어서 연결해줬다. 앤드포인트로 요청을 보내면 된다.✅ 참조 URL
https://www.notion.so/Next-js-7bd749f23bbb4745989e55d8d53cc44ehttps://seo.tbwakorea.com/blog/seo-guide-2022/
https://codingapple.com/unit/nextjs-image/
https://nextjs.org/docs/pages/api-reference/components/image
5.30 최근에 만들어지는 프로젝트들은 SEO를 위해서 거의 Next.js를 쓴다고 한다.. 우리 캠프에서는 next를 자세히 배우지 않아서 좀 아쉬운 마음도 들지만 일단 react를 확실히 할 줄 알아야 next도 활용 할 수 있는거니까 개념을 먼저 익혀두고 정규과정이 끝난후에 다시 next.js를 학습해야겠다고 생각했다.
5.31 page router는 익히기는 어려운데 익히고나면 뭔가 더 분명하게 next.js의 동작방식을 파악하기 용이해지는 것 같다. app router 개념만 살짝 봤을 때는 솔직히 이게 어떻게 ssr ssg를 구분한건지 잘 이해가 되지 않았다. 실습을 해보면 더 이해가 가려나?
6.1 next.js..레전드 3일컷.. 물론 다 배운게 아니라는건 알고있지만 기본적인거만 빠르게 알려주고 CRUD를 구현하는 과제까지 해야했다. 중간에 개념을 뛰어넘는게 너무 많아서 원래 어제까지의 일정이었지만 다 하지못해서 오늘 현재시각 새벽 4시까지 해서 겨우 일정을 끝마쳤다 ^_^..
이로서 정말로 리액트 + next.js 과정이 끝이났다.. 와 나 괜찮은걸까?!@ 속시원하다기 보다는 뭔가 불안함이 남는다. 당연히 언어를 익히는게 끝이 없다는 것도 알고 만드는 과정과 학습하는 과정은 동반되어야 한다는 것도 알지만..
안전벨트를 안메고 놀이기구에 탑승하는것 같은 불안한 마음이 자꾸 든다..크크.. 당장 다음주부터 미니 프로젝트를 시작하던데 나는 얼마나 헤매고 얼마나 성장할까?! 재밌을것도 같고.. 걱정도 되고.. 그래도 아무튼 한달간 매일매일 공부하고 블로그에 내용 추가하고.. 고3때보다 열심히 공부했다..모든 사람의 눈에 충분히 노력했다고 비춰지지 않을수도 있겠지만 그래도 내가 할 수 있는 만큼은 최선을 다했다. 고생했다 나자신아,,