Next.js 입문(2)
SeverSideRendering = Nextjs를 사용하면 그냥 자동으로 좋아지는 것
개발자 도구 들어가서 메뉴표시(점 세 개짜리) 누른 다음에 disablejavascript를 설정하면 해당 페이지가 자바스크립트를 지원하지 않는다.
하지만 nextjs는 서버쪽에서 실행시켜주기때문에 새로고침을 해도 렌더링되는 모습이 나타난다.
.next 폴더에 nextjs가 서버쪽에서 리액트를 실행해서 응답결과를 .next에 저장한다 그것을 응답하기 때문이다 nextjs는 자바스크립트가 아닌 HTML을 실행한다.
single Page Application
<a href> 형태로 페이지를 이동하는 경우에는 이동할 때 마다 처음부터 끝까지 모든 내용을 다시 다운받는다. 네트워크가 불안정하거나 인터넷이 느린 경우에는 사용자들이 느리다고 느낄 수 있고 서비스제공자에게는 돈이 많이 들 수 있다.
이미 방문한적 있는 페이지를 방문할 때 또 다시 페이지를 다운받는 단점도 있다.
<Link>태그를 사용하는 경우에는 링크에 마우스를 갖다 대기만 하여도 미리 백그라운드에서 해당 페이지를 다운로드를 받는다. 클릭을 하면 당연히 바로 나올 것이다. 이미 방문한 페이지를 방문할 때에는 다운로드를 받지도 않는 모습을 볼 수가 있다.
이렇게 웹페이지가 여러 페이지임에도 불구하고 하나의 페이지처럼 작동하는 것을 Single Page Aplication이라고 한다.
정적 자원 사용하기(이미지같은 것)
public폴더에 파일을 저장하고 <img src="/파일명.png"></img> 로 불러올 수 있다 /가 public폴더에 접근한다는 뜻이다.
CSS
global.css라는 파일은 전역적으로 디자인을 적용할 수 있는 위치에 있다.
Backend
백엔드를 구축해서 동적으로 내용을 표시해 보자.
json server라는 도구를 이용해서 구축을 한다.
npx json-server --port 9999 --watch db.json
9999번 포트에서 실행시키고 db.json파일에 정보를 저장하고 정보가 바뀌면 바로 서버에 저장하기 위해서 watch라는 옵션을 준다.(db.json의 정보가 바뀌면 서버가 재실행된다.)
api를 확인하고 만들어보자.
개발자도구 -> 네트워크 탭을 엶 -> esc를 누르면 밑에서 콘솔창이 나온다.
서버랑 통신할 때 사용하는 fetch명령을 사용해서 출력하게 해본다.
글목록 가져오기
사용자와 상호작용하는 기능은 클라이언트 컴포넌트 정보를 단순하게 보여주는 컴포넌트는 서버컴포넌트로 구현하는 것이 더 유리하다.
클라이언트 컴포넌트로 먼저 작성해보고 서버컴포넌트로 바꾸어 주는 작업을 해보자.
서버 컴포넌트에서 useState같은 api를 사용하면 에러가 뜬다
서버컴포넌트를 클라이언트 컴포넌트로 바꾸고 싶다면 "use client"를 제일 위에다가 작성하면 된다.
위에 있는 ol태그의 목록들은 자바스크립트가 실행되지 않으면 나타나지 않는다는 단점이 있다.
데이터베이스 관련 접근에 대해서도 보안쪽으로 위험이 있을 수 있다.
서버 컴포넌트는 서버쪽에서 fetch 메소드가 실행되고 실행이 끝날때까지 기다린다(await) 그리고 끝나면 json으로 바꾸라는 명령이 전달되면서 topic데이터를 가져온다. 그 데이터로 글 목록들을 동적으로 생성한 다음에 만들어진 결과를 서버쪽에(.next 폴더)저장해 놓고 최종적인 정적인 내용만 클라이언트로 전송한다 그 과정에서 자바스크립트같은 것들은 빼고 전송한다. 용량이 적어지고, 서버가 가깝게 있으면 동작이 빠르게 끝난다. 서버쪽에서 렌더링을 끝내고 데이터를 보내기 때문에 자바스크립트를 Disable시켜도 작동을 한다.
읽기
글 작성기능을 만들 때는 사용자와 상호작용 해야되기 때문에 서버클라이언트를 사용하지 않는다.
글이 생성되는 Create기능을 만들고 useRouter를 이용해서 글이 생성되면 해당 글의 페이지로 이동하게 된다.
cache
위를 살펴보면 글의 제목과 내용이 잘 추가가 되었고 해당 페이지로 잘 이동을 하였다.
하지만 위의 글 목록은 최신화가 되어있지 않다. 이 문제는 cache와 관련이 되어있다.
nextjs는 기본적으로 한 번 가져온 정보들을 저장해 둔다.
.next안에 저장된 정보가 보관되어 있다. 그 정보를 지우고 다시 한 번 접속을 해보겠다.
rmdir /s /q .next 라는 명령어로 파일을 삭제하고 npm run dev로 개발환경을 시작하고 페이지를 리로드해본다.
cashe가 miss면 cache를 사용하지 않고 새로 만들었다는 뜻이고 Hit이면 cache를 사용했다는 것이다.
cache가 Hit이면 새로고침을 해도 서버터미널창에서 통신을 하지 않는 모습을 볼 수가 있다.
성능 조금 희생하고 조금 단순하게 해결한 모습이다.
create를 하면 글목록을 담당하고 있는 데이터가 cache되고 있지 않기 때문에 router.refresh()를 하면 서버 컴포넌트가 새로 데이터를 가지고와서 결과를 나타내주게 된다.
cache정책이 여간 복잡한게 아니다 cache를 끄고 하다가 공부하고 cache를 최대로 활용하면 퍼포먼스가 굉장히 증가될 것이다.
update / delete 버튼 구현
update/delete 버튼은 해당 글에 들어가면 보이게 해야 한다.
layaout.js는 read/[id] 폴더의 밖에 있기 때문에 props로 id값을 쓸 수 없다.
이럴때는 useParams api를 사용해야한다.
하지만 layout.js는 서버클라이언트이기때문에 사용이 제한된다.
그래서 글 목록을 컴포넌트로 만들고 다른 파일에 옮겨준다.(Control.js)
그리고 해당 글에 들어가서 update 버튼을 누르면 이동되는 주소값도 update+id로 동적으로 바꾸어 주었다.
useEffent를 사용해서 id값에 맞는 데이터를 가져오고 useState를 이용해서 변수에 넣어준다.
title과 body에 해당하는 태그의 value값을 변수에 맞게 넣어주고 onChange를 사용해서 수정할 수 있게 해준다.
이렇게만 하면 바꾸어 지긴 하나 글의 본문의 내용은 바로 바뀌어 지진 않는다.(cache때문임)
글 본문의 데이터를 받아올때 cache를 끄고 실행하면 글을 수정하자마자 글 본문에도 바로 반영이 된다.
글 삭제
Controljs에서 delete부분에 onClick메서드를 추가한다 options변수를 만들어 메소드를 DELETE로 설정하고 fetch부분에 적용을 시켜준다 글이 삭제되고 나서는 해당 글의 페이지를 보여주면 안되므로 홈으로 리다이렉트를 하고 새로고침을 시켜준다 그러면 홈페이지에서 글 목록이 사라진다.
환경변수
현재 개발된 코드를 보면 로컬호스트가 하드코딩 되어있다. 그런데 실제 개발할때 사용되는 api와 서버에 디플로이에서 실서버에서 사용되는 주소 api가 다를 수 있다. 이런 정보를 애플리케이션 소스코드에서 떨어트려서 관리해야될 필요성을 느낄 것이다.
환경변수 사용하는 법은 프로젝트 폴더 위치에서 .env.local파일을 만들어주고 어플리케이션에서 사용하는 정보들을 적으면 된다.
NEXT_PUBLIC을 빼고 유저클라이언트에서 찍어보면 undifined가 나온다.
기본적으로 환경변수에는 패스워드같은 기밀이 중요한 데이터가 포함될 가능성이 높다.
그런 기밀정보까지 클라이언트 컴포넌트에 노출이 된다면 정보가 브라우저로 전송이 될 것이고 그 말은 정보가 유출이 된다는 뜻이다. 이런 문제를 막기위해 기본적으로 환경변수는 서버컴포넌트에서만 접속이 가능하다.
웹브라우저를 위한 환경변수를 쓰고싶다면 NEXT_PUBLIC를 접두사로 붙여야만 한다.
버전관리 할때는 .gitignore를 보면 nextjs에서 버전관리를 하지말라고 권고한 내용중에 .env가 있을 것 이다.
그래서 기본적으로 nextjs는 .env.local을 버전관리 못하게 막아 놓았다.
.env.local.example과 같은 샘플환경을 만들고 샘플 정보를 담아놓는다. 그러면 나중에 다른사람이 이 개발환경을 다운로드 받아서 설치할때 저 파일을 .env.local로 바꾼다음에 자기한테 맞는 정보들로 바꾸거나 추가하고 개발환경이나 실서버를 구축할 수 있다. 그런다음 커밋을 하면 된다.
느낀점.
전에 웹프로젝트를 했을 때 다루었던 것들이 반복되는 편이었다.(react로만 개발했었음)
그때는 기본적인 기능들을 대충아는 정도에서 멈추었다면 이번 공부를 통해 "왜" "어떻게"를 공부할 수 있어서 좋았다.
한시간 반 정도의 강의를 블로그에 정리하면서 완벽히 이해하고 넘어가려다 보니 4시간 정도 공부한 것 같다...