가장 큰 근본적 차이는 CRA는 클라이언트 사이드, Next js는 서버사이드 랜더링이라는 점이다.
CRA의 단점은 아래와 같다.
client 사이드의 경우, 처음 화면에서 서버에서 가져오는 정보로 다시 화면을 재구성하게 되는데 이 때 처음 가져올 때랑 refresh할 때마다 flickering (깜박임)과 같은 현상이 일어난다. 개발자는 이 문제를 해결하기 위해 cache를 사용해야하는 등 다양한 방법을 강구해야한다.
SEO엔진이 CRA사이트의 경우엔 텅빈 html돔만 보게된다. 이는 SEO가 불가능하게 만든다.
물론 이를 극복하기 위해 meta 태그를 중간중간 넣는 방법이 있긴하다. 허나 페이지마다 이 태그 설정을 해야하는데 이는 개발자를 귀찮게 한다.
Next js는 서버사이드 랜더링으로 이를 모두 해결한다. 그리고 편리한 장점들이 더 있다.
pre-rendering
미리 서버에서 랜더링해서 클라이언트에 넘겨준다. 그렇기 때문에 flickering도 없고 SEO 에도 좋다.
file-based routing
CRA와 같은 경우엔 router를 관리해야한다. 헌데 Next js는 파일 구성으로 이 라우팅을 간단하게 해결한다.
이걸 보면 news/something 라우팅이랑 news/1, news/2와 같은 파라미터가진 라우팅을 파일 구조로 해결한다. 코드도 덜 쓰고 서비스의 구조를 이해하기에도 직관적이다.
아래는 api 폴더 내부의 핸들러이다.
// /api/new-meetup
// POST /api/new-meetup
async function handler(req, res) {
if (req.method === 'POST') {
const data = req.body;
const client = await MongoClient.connect(
'url'
);
const db = client.db();
const meetupsCollection = db.collection('meetups');
const result = await meetupsCollection.insertOne(data);
client.close();
res.status(201).json({ message: 'Meetup inserted!' });
}
}
export default handler;
node js 사용해본 사람이라면 req.body, res.status와 같은 게 익숙할 것이다. next js에서 api를 제작해서 서비스 내부에서 사용이 가능하다.
그리고 CRA와 같은 경우엔 useEffect 부분에 비동기 서버 부분을 처리한다. 그래서 서버 api부분과 돔을 구현할때 사용되는 로직이 혼재되어 있다. 그런데 next js는 두가지 방식으로 따로 서버에서 처리해서 정보를 가져온 후 prerendering을 진행한다.
// posts will be populated at build time by getStaticProps()
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}
// This function gets called at build time on server-side.
// It won't be called on client-side, so you can even do
// direct database queries.
export async function getStaticProps() {
// Call an external API endpoint to get posts.
// You can use any data fetching library
const res = await fetch('https://.../posts')
const posts = await res.json()
// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts,
},
revalidate: 10,
}
}
export default Blog
빌드할 때 실행된다. 서버사이드에서 데이터를 받은 뒤 page에 props로 내린다. useEffect로 따로 받을 필요가 없다. useEffect 디펜던시 때문에 스트레스 받던거 생각하면 아주 편리하다.
function Page({ data }) {
// Render data...
}
// This gets called on every request
export async function getServerSideProps(context) {
// Fetch data from external API
const req = context.req;
const res = await fetch(`https://.../data`)
const data = await res.json()
// Pass data to the page via props
return { props: { data } }
}
export default Page
GetServersidProps는 request가 올 때마다 작동,
req, res 등을 사용할 수 있어 auth 관련된 로직을 관리하는 데 편하다.
모든 request때마다 새로 받아온다고 보면 된다.
단점은 getStaticProps는 캐쉬가 되어서 한번 받아오면 되는데 getserversideprops는 매번 다시 받아와야 한다.
위의 내용만 봐도 기존 CRA 방식과는 완전히 다르다. useEffect로 비동기 처리를 의존하던 때보다 훨씬 nextjs가 체계적이고 side effect를 줄일 수 있어 보인다.