next app을 설치하고 터미널에 next start를 입력하면 아래와 같은 에러를 마주할 수 있다
Could not find a production build in the '/Users/xxxxx/xxxxx/test-next-js/.next' directory.
Try building your app with 'next build' before starting the production server.
https://nextjs.org/docs/messages/production-start-no-build-id at NextNodeServer.getBuildId
(/Users/xxxxx/xxxxx/test-next-js/node_modules/next/dist/server/next-server.js:349:23)
해당 오류 메시지는 build 없이 Next.js 프로덕션 서버를 시작해서 발생한다. 프로덕션 서버를 시작하기 전에 next build 명령을 사용하여 Next.js 응용 프로그램을 빌드해야 한다. 이 명령은 프로덕션을 위해 코드를 컴파일하고 최적화한다고 한다.
문제를 해결하려면 다음 단계를 따르자:
terminal 또는 command prompt를 연다
Next.js 프로젝트의 root directory 로 이동한다.
다음 명령어를 실행한다. 이 명령어는 루트 root directory에 production build를 생성한다.
next build
4.build에 성공하면 next start 명령어를 실행할 수 있다.
하지만나는다음과같은문제를만났다.
bash: next: command not found
이 경우는 CLI 환경에서 다음 명령을 인식할 수 없음을 의미한다. 일반적으로 필요한 dependency 또는 pakage가 설치되지 않았거나 Node.js 환경에 문제가 있을 때 발생한다고 한다.
문제를 해결하려면 다음 단계를 따르자:
1. 시스템에 Node.js가설치되어있는지확인해보자. 터미널에서다음명령을실행하여 Node.js가설치되어있는지확인할수있다.
node -v
Node.js가 설치되지 않은 경우, 공식 Node.js 웹사이트(https://nodejs.org)에서 Node.js를 다운로드하여 설치하자.
my-name-ui-MacBookPro:test-next-js my-name$ yarn next start
yarn run v1.22.18
$ /Users/my-name/workspace/test-next-js/node_modules/.bin/next start
- ready started server on 0.0.0.0:3000, url: http://localhost:3000
// 기본 styled-components
npm i styled-components @types/styled-components
yarn add styled-components @types/styled-components
//스타일이 적용되기 전에 렌더링되는 현상을 방지하고, 문자열 안에 스타일 들어가는 것 처리를 위한 설치
yarn add -dev babel-plugin-styled-components
//전역 스타일링에서 이용하기 위함
yarn add styled-reset
파일구조
public
├── images
├── css
└── data //간단한 페이지를 만들 때 저장할 데이터
// 어플리케이션의 기능에 사용되는 소스들
src
├── component // 컴포넌트와 컨테이너 파일들
│ ├── common // 공통적으로 사용되는 컴포넌트들(ex button, modal)
│ └── layout // 각 페이지들의 전체 레이아웃이자 컴포넌트들의 모임
│ ├── app
│ ├── home
│ └── directory
│
├── pages // 페이지를 담당하는 컴포넌트(폴더구조로 url 결정)
│ └── [id]
│
├── core
│ ├── config // 어플리케이션에서 사용되는 설정들 모임
│ ├── provider
│ │ ├── helper // store를 이용하는 공통 로직들 정리
│ │ └── provider // store의 값들을 컨테이너에게 전달해 줌
│ ├── redux // Ducks 패턴으로 redux를 정의
│ └── api // axios를 이용하여 서버와의 통신 로직을 담당
│
├── util
│ ├── hooks // 각 컴포넌트에서 사용되는 공통 로직들을 커스텀 훅으로 관리
│ └── reduxUtils // redux ducks 패턴에서 사용되는 유틸함
│
│
└── styles
├── global-style.ts // 전역 스타일 설정
└── theme.ts // 공통적으로 사용할 스타일을 지정하는 부분
_document.tsx 파일 추가
_document.tsx파일에 css를 미리 적용할 수 있다.
next.js에서 styled component를 적용할 때 css 로딩 지연으로 깜빡이는 모습을 방지하기 위함이다. _document.tsx 파일 _document.js 파일은 pages폴더 내부에 존재하는 모든 페이지에 global한 설정값을 줄 수 있는 파일이다. 최상위 디렉토리에 _document.tsx 파일을 생성해서 아래 코드를 넣어준다.
이 글에 들어가기 앞서 먼저 알아두면 좋은 개념을 설명 합니다. 아시는 분은 넘어가도 됩니다.
context : 함수를 호출한 object
scope : 현재 실행되는 context로 여기서 context는 값과 표현식이 표현되거나 참조 될 수 있는 것을 의미 한다.
lexical scope(stactic scope): 함수나 변수의 scope를 호출된 곳이 아닌 정의 된 곳을 기준으로 정함.
dynamic scope : 함수나 변수의 scope를 호출된 라인을 기준으로 정함.
this : 함수 내에서 함수를 호출한 context를 뜻한다.
화살표 함수에서는 자신을 감싼 stactic scope, 전역 코드에서는 global object를 가리킨다
bind :
ECMAScript5에서 도입되었습니다. f.bind(someObject)를 호출하면 f와 같은 본문(코드)과 범위를 가졌지만 this는 원본 함수를 가진 새로운 함수를 생성합니다. 새 함수의 this는 호출 방식과 상관없이 영구적으로bind()의 첫 번째 매개변수로 고정됩니다.
일반 함수와 화살표 함수 사이에는 큰 차이가 있습니다. 어떤 상황에서는 훨씬 효과적이지만 어떤 때에는 그렇지 못합니다.
Javascript 화살표 함수는 함수를 작성하는 더욱 효과적인 방법으로 ES2015에서 도입되었습니다. 아래 코드 예시에서 foo와 bar는 같은 기능을 합니다.
let foo = function() {
console.log('BAZ')
}
let bar = () => {
console.log('BAZ')
}
foo() // BAZ
bar() // BAZ
하지만 화살표 함수는 단순히 function 으로 표현되는 함수의 syntactic sugar(같은 기능을 하지만 더 쉽게 작성할 수 있는 새로운 문법)가 아닙니다. 여기엔 반드시 알아야하는 큰 차이가 있습니다. 이 차이는 화살표 함수를 더 멋지게 만들지만, 제대로 알고 쓰지 않으면 문제가 생길 수 있습니다. 이 경우 화살표 함수로 해결할 수 없으므로 function 함수 식을 사용해야 합니다.
화살표 함수와 this
function 함수 표현에서 this 키워드는 함수가 호출된 context에 따라 바인드 됩니다. 반면 화살표 함수는 lexical scope에서 이 값을 사용합니다. 이 차이로 다른 동작을 하게 됩니다. context는 어떻게 호출되었는지가 중요하고 scope는 어떻게 정의되었는지가 중요합니다.
obj는 myFunc를 호출합니다. obj는 myFunc의 context입니다. 그래서 myFunc에서 this의 값이 obj에 바인딩됩니다. context는 어떻게 호출되냐에 따라 다르게 정의될 수 있습니다. 예를 들어, constructor가 new 라는 keyword와 함께 호출될 때 this는 생성된 object를 일컫습니다. context에 대한 자세한 사항은
myFunc에서 this의 값은 obj를 가리킵니다. 즉 myFunc.myVar의 결과를 보면 'foo'가 출력됩니다. 그러나 두번째 함수는 setTimeout에 의해 호출됩니다. 여기 context는 다릅니다. 여기서 context는 Node의 Timeout object 또는 브라우저의 window ojbect를 뜻합니다. 그런 이유로 우리는 this를 obj로 생각했지만 결과를 보면 우리가 의도한 this의 값은 undefined로 출력됩니다.
우리가 의도한대로 값을 얻기 위해선 몇가지 방법을 사용해야합니다. 첫번째 방법은 this를 대게 self나 that이라는 이름으로 명명하는 변수에 할당하는 방법입니다. 해당 변수는 callback 함수의 lexical scope안에 있습니다. 이는 callback 함수가 scope안에서 정의되었기 때문에 위에서 만들었던 변수에 접근할 수 있음을 의미합니다.
let obj = {
myVar: 'foo',
myFunc: function() {
let self = this console.log(this.myVar)
setTimeout(function() {
console.log(self.myVar)
}, 1000)
}
}obj.myFunc() // foo ... then... foo
우리는 딱봐도 화살표 함수가 callback 함수에 적합하다는 것을 알 수 있습니다. 그러나 우리가 화살표 함수를 object method로 사용하게 된다면 어떻게 될까요 ?
위와 같은 코드를 보면 this가 obj를 말한다고 생각할 수 있습니다. 하지만 여기서 this는 화살표 함수를 호출한 obect에 바인딩하지 않습니다. 화살표 함수는 this의 값을 자기 자신이 정의된 scope의 값을 사용합니다. 여기서는 global object를 일컫습니다. 그래서 화살표 함수는 object method로 사용될 수 없습니다.
function 함수는 object method로 적합하고, 화살표 함수는 callback 함수나 map과 같은 method에 가장 적합합니다.
기본적으로 화살표 함수는 자신의 scope에서 this 값과 다른 값을 바인딩할 수 없습니다. 따라서 bind(), call(), apply() method는 여기의 값에 영향을 주지 않습니다.
생성자(constructor)
화살표 함수가 object에서 제대로 작동하지 않게하는 다른 방법이 있습니다. 이 것들은 constructor가 될 수 없습니다. function 함수 표현식은 새로운 obect를 생성할때 다음과 같이 사용됩니다.
let Person = function(name, height) {
this.name = name
this.height = height
}Person.prototype.hello = function() {
console.log('Hi, my name is ' + this.name)
}let alice = new Person('Alice', 1.7)
alice.hello() // Hi, my name is Alice
하지만 화살표 함수는 prototype이라는 property를 가지고 있지 않아서 new와 같이 사용될 수 없습니다.
arguments 바인딩
화살표 함수가 this를 바인딩하지 못하며 단지 자신의 scope의 this 값을 사용한다는 것을 보았다. 화살표 함수는 또한 argument object를 바인딩하지 못한다. function 함수 표현으로는 다음과 같이 할 수 있다.
let sum = function() {
// arguments is available return args.reduce((a, b) => a + b, 0)
let args = Array.from(arguments)
}
sum(1, 2, 3) // 6
화살표 함수는 arguments object가 없다. 하지만 나머지 연산자를 사용해서 같은 기능을 할 수 있다. 코드는 다음과 같다.
let sum4 = (...args) => {
return args.reduce((a, b) => a + b, 0)
}sum(1, 2, 3) // 6
암묵적으로 값을 반환
우리는 위에서 함수를 화살표 함수로 더욱 간결하게 선언할 수 있었습니다. 이 간결한 형식을 사용하면 block에 코드를 감싸지 않아도 됩니다. 함수를 정의하면 화살표 함수가 값을 반환해주기 때문이죠!
let sum = (...args) => args.reduce((a, b) => a + b, 0)
또한 개체 리터럴을 괄호로 묶어서 반환할 수 있습니다.
let getObj = () => ({ foo: 'hello', bar: 'world' })
이 간결한 문법은 화살표 함수를 작고 가독성이 좋은 callback 함수를 정의하는 데에 탁월하게 만듭니다.
요약
화살표 함수는 기존 function 함수 표현과 꽤 다릅니다. 화살표 함수는 callback 함수와 같이 잘 작동하게 하는 몇가지 탁월한 property가 있습니다. 하지만 object methods나 생성자로 쓰이기엔 적절하지 못합니다. 여기엔 몇가지 차이가 존재합니다. 예를들어 화살표 함수는 generators가 될 수 없습니다. 아래 MDN 문서에서 더 자세하게 보시길 바랍니다!