[Next.js] 공식문서 : Foundation

👾·2023년 6월 21일
2

Next.js

목록 보기
1/4
post-thumbnail

About Next.js

Introduction

Next.js를 효과적으로 사용하기 위해서는, JavaScript, React, 그리고 관련된 웹 개발 개념들에 익숙해지는것이 도움이 된다. 하지만 JavaScript와 React는 매우 방대한 토픽이다. 언제 Next.js를 배울 준비가 되었을지를 알 수 있겠는가?

Next.js Foundations 코스에 온 걸 환영한다! 비기너들에게 친화적이고, 예제 중심의 이 코스는 Next.js의 필수 지식 위주로 안내한다. 당신은 간단한 프로젝트를 단게별로 만들어볼 수 있다; JavaScript 애플리케이션에서 시작해서, React와 Next.js로 마이그레이션한다.

각 섹션은 이전 섹션을 기반으로 만들어졌기 때문에, 이미 알고 있는 내용에 기반하여 시작할 지점을 선택할 수 있다.

이 튜토리얼은 HTML, CSS, JavaScript를 알고있고, React에 대해 전혀 알고있지 않다고 가정한다. 이미 React에 익숙하다면, `Getting Started with Next.js` 섹션이나 `Create your first Next.js app` 섹션으로 바로 넘어갈 수 있다.

What is Next.js?

Next.js는 빠르게 웹 애플리케이션을 만들기 위한 building block을 제공하는 유연한 React framework다.

하지만 정확히 이것이 무엇을 의미하는걸까? React와 Next.js가 무엇인지 그리고 이들이 어떤 도움을 줄 수 있는지 알아보는 시간을 가져보자.

Building Blocks of a Web Application

모던 애플리케이션을 만들기 위해 고려해야할 몇가지가 있다. 예를들어:

  • User Interface - 유저가 애플리케이션을 사용하고 상호작용하는 방법
  • Routing - 유저가 애플리케이션에서 다른 부분들간에 탐색하는 방법
  • Data Fetching - 데이터가 어디에 살아있고 어떻게 가져오는지
  • Rendering - 정적 또는 동적 컨텐츠를 렌더링하는 시기와 위치
  • Integrations - 어떤 thrid-party 서비스를 사용하는지 (CMS, auth, payments 등) 그리고 그들과 연결하는 방법
  • Infrastructure - 애플리케이션 코드를 어디에 배포, 저장, 실행하는지 (서버리스, CDN, Edge 등)
  • Performance - 엔드유저 단에서 애플리케이션을 어떻게 최적화하는지
  • Scalability - 팀, 데이터, 트래픽이 증가할때 애플리케이션이 어떻게 적응하는지
  • Developer Experience - 애플리케이션을 만들고 유지보수하는 팀의 경험

애플리케이션의 각 부분에서, 솔루션을 직접 만들 것인지 또는 라이브러리나 프레임워크 등의 다른 도구를 사용할지 결정해야한다.

What is React?

React는 대화형 유저 인터페이스를 만들기 위한 JavaScript 라이브러리이다.

유저 인터페이스란, 사용자가 화면에서 보고 상호작용하는 요소를 의미한다.

라이브러리란, React는 UI를 만드는데 효과적인 기능들을 제공하지만, 이 기능들을 애플리케이션의 어디에서 사용할지는 개발자에게 맡긴다는 의미이다.

React의 성공 중 하나는, 애플리케이션 구축의 다른 측면에 대해서 비교적 의견이 없다는 점이다. 이것은 thrid-pary 도구와 솔루션들이 번성하는 생태계를 만들어냈다.

그러나 이는 또한 완전한 React 애플리케이션을 처음부터 만들어내기 위해서는 약간의 노력이 필요하다는 의미이기도 하다. 개발자들은 일반적인 애플리케이션 요구사항에 맞게 도구를 구성하고 솔루션들을 재발명하는데 시간을 써야 한다.

What is Next.js?

Next.js는 웹 애플리케이션을 만들기 위한 building blocks을 제공하는 React 프레임워크이다.

프레임워크란, Next.js가 React에 필요한 도구와 구성들을 다루고, 추가적인 구조, 기능을 제공 및 애플리케이션 최적화를 제공한다는 의미이다.

당신은 UI를 만들기 위해 React를 사용하면서, Next.js의 기능들을 점진적으로 채택하여 라우팅, 데이터 fetching, 통합등과 같은 일반적인 애플리케이션 요구사항들을 해결할 수 있다. - 동시에 개발자와 최종 사용자 경험을 개선할 수 있다.

당신이 개인 개발자거나 큰 팀의 일원이든 관계없이, React 및 Next.js를 활용하여 완전히 interative한, 매우 동적이고 효율적인 웹 애플리케이션을 구축할 수 있다.

From JavaScript to React

어떻게 React가 동작하는지 이해하기 위해서는, 먼저 브라우저가 대화형 UI를 만들기 위해서 어떻게 코드를 해석하는지에 대한 기본적인 이해가 필요하다.

유저가 웹페이지에 방문하면, 서버는 아마도 다음처럼 생긴 브라우저에게 HTML 파일을 반환한다:

그리고 브라우저는 HTML을 읽고 Document Object Model (DOM)을 구성한다.

What is the DOM?

DOM은 HTML 요소들의 객체 표현이다. 이는 당신의 코드와 UI간의 다리 역할을 하며, 부모-자식 관계를 가지는 트리같은 구조를 가진다.

JavaScript와 같은 프로그래밍 언어와 DOM 메소드를 사용하여 유저 이벤트를 감지하거나 유저 인터페이스 안의 특정한 요소를 선택하고, 추가하고, 수정하고, 삭제하면서 DOM을 조작할 수 있다. DOM 조작은 특정 요소를 target으로 지정할 수 있을 뿐만 아니라, 스타일과 내용도 바꿀 수 있게 한다.

Updating the UI with JavaScript

Updating the UI with JavaScript and DOM Methods

h1 태그를 추가하기 위해 어떻게 JavaScript와 DOM 메소드를 사용하는지 알아보자.

코드 에디터를 열고 index.html파일을 만들어라. html 파일 안에 아래 코드를 추가해라:

<!-- index.html -->
<html>
  <body>
    <div></div>
  </body>
</html>

div에 고유한 id를 줘서 나중에 이를 지정할 수 있게 하자.

<!-- index.html -->
<html>
  <body>
    <div id="app"></div>
  </body>
</html>

HTML 파일 안에 JavaScript를 작성하려면, script 태그를 추가해라.

<!-- index.html -->
<html>
  <body>
    <div id="app"></div>
    <script type="text/javascript"></script>
  </body>
</html>

이제, script 태그 안에서, id를 이용해 <div> 태그를 선택하기 위해 getElementById() DOM 메서드를 사용할 수 있다.

<!-- index.html -->
<html>
  <body>
    <div id="app"></div>

    <script type="text/javascript">
      const app = document.getElementById('app');
    </script>
  </body>
</html>

계속해서 새로운 <h1> 요소를 만들기 위한 DOM 메서드를 사용할 수 있다.

<!-- index.html -->
<html>
  <body>
    <div id="app"></div>

    <script type="text/javascript">
      // Select the div element with 'app' id
      const app = document.getElementById('app');

      // Create a new H1 element
      const header = document.createElement('h1');

      // Create a new text node for the H1 element
      const headerContent = document.createTextNode(
        'Develop. Preview. Ship. 🚀',
      );

      // Append the text to the H1 element
      header.appendChild(headerContent);

      // Place the H1 element inside the div
      app.appendChild(header);
    </script>
  </body>
</html>

잘 동작하는지 확인하기 위해서, HTML 파일을 브라우저에서 열어라. 'Develop. Preview. Ship. 🚀'이라는 h1 태그를 확인할 수 있어야 한다.

HTML vs the DOM

브라우저 개발자 도구로 DOM 요소 내부를 살펴보면, DOM이 <h1> 요소를 포함하고 있는 것을 확인할 수 있다. 페이지의 DOM은 소스코드와 다르다 - 즉, 우리가 생성한 원본 HTMl 파일과 다르다.

이는 HTML은 최초의 페이지 컨텐츠를 보여주기 때문이고, DOM은 우리가 작성한 자바스크립트 코드에 의해 변경된, 업데이트된 페이지 컨텐츠를 보여주기 때문이다.

순수한 JavaScript로 DOM을 업데이트하는건 매우 강력하지만 장황하다. 일부 텍스트가 포함된 <h1> 요소를 추가하기 위해 이 모든 코드를 작성해야한다 :

<!-- index.html -->
<script type="text/javascript">
  const app = document.getElementById('app');
  const header = document.createElement('h1');
  const headerContent = document.createTextNode('Develop. Preview. Ship. 🚀');
  header.appendChild(headerContent);
  app.appendChild(header);
</script>

앱과 팀의 규모가 커질수록, 이 방식으로 애플리케이션을 만드는 것은 점점 힘들어질 것이다.

이 접근법을 사용하면, 개발자는 컴퓨터에게 어떻게 해야하는지에 대해서 설명하기 위한 명령어들을 작성하는데 많은 시간을 쏟을 것이다. 하지만 내가 무엇을 보여주고 싶은지를 설명하고 컴퓨터가 DOM을 어떻게 업데이트하는지 알아내는것이 더 좋지 않을까?

Imperative vs Declarative Programming

위의 코드는 imperative programming(명령형 프로그래밍)의 좋은 예시다. 어떻게 유저 인터페이스가 업데이트 되어야하는지에 대한 단계를 작성하고 있다. 하지만 유저 인터페이스를 구축할 때, 개발 프로세스 속도를 높일 수 있기 때문에 선언형 접근방식이 선호되는 경우가 많다. DOM 메서드를 작성하는 대신, 개발자들이 무엇을 보여주고 싶은지 선언할 수 있다면 매우 효율적일 것이다. (지금 상황에서는, 텍스트를 포함한 h1 태그)

명령형 프로그래밍은 피자를 어떻게 만드는지에 대한 단계별 명령을 셰프에게 전달하는 것이다. 선언형 프로그래밍은 피자를 만드는데 필요한 단계들에 대한 걱정 없이 피자를 주문하는 것이다.

개발자가 유저 인터페이스를 만들기 위해 도움이 되는 가장 유명한 선언형 라이브러리는 React이다.

React: A declarative UI library

개발자로서, 유저 인터페이스에 무엇이 일어나기를 원하는지 React에게 알려줄 수 있고, React는 당신을 대신해 DOM을 업데이트하기 위해서 어떻게 해야하는지에 대한 단계를 알아낼 것이다.

Getting Started with React

프로젝트에서 React를 사용하기 위해선, unpkg.com이라 부르는 외부 웹사이트에서 React 스크립트 두개를 로드하면 된다.

  • react는 React 라이브러리의 코어 부분이다.
  • react-dom은 DOM과 함께 React를 사용할 수 있게 하는 DOM 전용 메소드들을 제공한다.
<!-- index.html -->
<html>
  <body>
    <div id="app"></div>

    <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>

    <script type="text/javascript">
      const app = document.getElementById('app');
    </script>
  </body>
</html>

일반 JavaScript로 DOM을 직접 조작하는 대신, react-domReactDOM.render() 메서드를 사용하여 React에게 우리의 #app 엘리먼트 안에 <h1> 타이틀을 렌더링해달라고 지시할 수 있다.

<!-- index.html -->
<html>
  <body>
    <div id="app"></div>

    <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>

    <script type="text/javascript">
      const app = document.getElementById('app');
      ReactDOM.render(<h1>Develop. Preview. Ship. 🚀</h1>, app);
    </script>
  </body>
</html>

그러나 브라우저에서 이 코드를 실행하려고 하면 구문 오류가 발생한다.

<h1>...</h1>은 유효한 JavaScript가 아니기 때문이다. 이 코드는 JSX이다.

What is JSX?

JSX는 친숙한 HTML 유사 구문으로 UI를 표현할 수 있도록 하는 JavaScript의 확장 문법이다. JSX의 좋은 점은 *3가지 JSX 규칙을 따르는것 외에도 HTML과 JavaScript 밖의 새로운 문법이나 기호를 배울 필요가 없다는 점이다.
(*1. single root element를 반환할 것 / 2. 모든 태그를 닫을 것 / 3. 거의 모든것을 camelCase로 작성할 것)

기본적으로 브라우저는 JSX를 이해하지 못하므로, JSX 코드를 일반 JavaScript로 변환하려면 Babel과 같은 JavaScript 컴파일러가 필요하다.

Adding Babel to your project

프로젝트에 Babel을 추가하려면, index.html 파일 안에 다음 script를 복사 붙여넣기 해라.

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

추가로, script 타입을 type=text/jsx로 변환하여 Babel에게 어떤 코드를 변환할 것인지 알려줘야 한다.

<html>
  <body>
    <div id="app"></div>
    <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
    <!-- Babel Script -->
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script type="text/jsx">
      const app = document.getElementById('app');
      ReactDOM.render(<h1>Develop. Preview. Ship. 🚀</h1>, app);
    </script>
  </body>
</html>

그러면 이제 잘 작동하는지 확인하기 위해 브라우저에서 코드를 실행할 수 있다.

방금 작성한 선언적 React 코드를 비교하면 다음과 같다.

<script type="text/jsx">
  const app = document.getElementById("app")
  ReactDOM.render(<h1>Develop. Preview. Ship. 🚀</h1>, app)
</script>

이전 섹션에서 작성했던 명령형 JavaScript 코드와 비교해보자 :

<script type="text/javascript">
  const app = document.getElementById('app');
  const header = document.createElement('h1');
  const headerContent = document.createTextNode('Develop. Preview. Ship. 🚀');
  header.appendChild(headerContent);
  app.appendChild(header);
</script>

React를 사용하여 반복되는 많은 코드를 제거할 수 있는 방법에 대해서 알 수 있다.

이것이 React가 하는일이다, 당신을 대신하여 작업을 수행하는 재사용가능한 코드 스니펫들을 포함하고 있는 라이브러리이다 - 이 경우에서는, UI를 업데이트한다.

Essential JavaScript for React

JavaScript와 React를 동시에 배울 수도 있지만, JavaScript에 익숙해지면 React를 더 쉽게 배울 수 있다.

다음 섹션에서, JavaScript 관점에서 React의 몇가지 핵심 개념들을 소개할 것이다. 언급될 JavaScript 주제들에 대한 요약은 다음과 같다 :

  • 함수와 화살표 함수
  • 객체
  • 배열과 배열 메소드
  • 비구조화
  • 템플릿 리터럴
  • 삼항연산자
  • ES 모듈과 import/export 문법

이 과정에서 JavaScript에 대해 깊게 들어가진 않지만, JavaScript 최신 버전에 대해 새롭게 익히는것이 좋다. 하지만 아직 JavaScript에 능숙하지 않다고 느낀다면 그게 React로 개발하기를 시작하는데 방해가 되지 않도록 하자!

React Core Concepts

React 애플리케이션을 만들기 시작하는데 익숙해져야할 React의 핵심 개념 3가지는 다음과 같다:

  • component
  • props
  • state

다음 섹션에서 위 개념들에 대해 알아보고 계속해서 배울 수 있는 리소스를 제공할 것이다.

Building UI with Components

유저 인터페이스는 컴포넌트라 부르는 더 작은 building block들로 나눌 수 있다.

컴포넌트를 통해 독립적이고 재사용가능한 코드 스니펫을 만들 수 있다. 컴포넌트를 레고 블럭처럼 생각하면, 이 개별적인 블록들을 가지고 조합해서 더 큰 구조를 만들 수 있다. UI의 일부분을 수정하고 싶으면, 특정한 컴포넌트나 블록을 수정하면 된다.

이 모듈성은 애플리케이션의 다른 부분을 건드리지 않고 쉽게 컴포넌트를 추가, 수정, 삭제할 수 있게 하므로 코드가 확장함에 따라 보다 잘 유지보수할 수 있다.

React 컴포넌트의 좋은 점은 바로 JavaScript라는 점이다. JavaScript 관점에서 React 컴포넌트를 어떻게 작성할 수 있는지 알아보자:

Creating components

React에서 컴포넌트는 함수이다. script 태그 안에, header 함수를 작성하자:

<script type="text/jsx">
  const app = document.getElementById("app")


  function header() {
  }

  ReactDOM.render(<h1>Develop. Preview. Ship. 🚀</h1>, app)
</script>

컴포넌트는 UI element를 반환하는 함수이다. 함수의 return문 안에 JSX를 작성할 수 있다:

<script type="text/jsx">
  const app = document.getElementById("app")

  function header() {
     return (<h1>Develop. Preview. Ship. 🚀</h1>)
   }

  ReactDOM.render(, app)
</script>

이 컴포넌트를 DOM에 렌더링하려면, ReactDOM.render() 함수의 첫번째 인자로 넘겨주면 된다:

<script type="text/jsx">

  const app = document.getElementById("app")

  function header() {
     return (<h1>Develop. Preview. Ship. 🚀</h1>)
   }


   ReactDOM.render(header, app)
</script>

하지만 잠깐, 이 코드를 브라우저에서 실행하려고 하면 에러가 발생할 것이다. 동작하게 하기 위해서 해야할 2가지 일이 있다:

첫번째로, React 컴포넌트는 일반 HTML과 JavaScript와 구분하기 위해서 대문자로 시작해야한다.

function Header() {
  return <h1>Develop. Preview. Ship. 🚀</h1>;
}

// Capitalize the React Component
ReactDOM.render(Header, app);

두번째로, <>를 사용하여 일반적인 HTML 태그를 사용하는 것처럼 React 컴포넌트를 사용해야한다.

function Header() {
  return <h1>Develop. Preview. Ship. 🚀</h1>;
}

ReactDOM.render(<Header />, app);

Nesting Components

애플리케이션은 보통 단일 컴포넌트보다 더 많은 내용으로 이루어져 있다. 일반적인 HTML 요소를 사용하는 것처럼, React 컴포넌트들을 서로 중첩할 수 있다.

예제에서, 새 컴포넌트 HomePage를 만들자:

function Header() {
  return <h1>Develop. Preview. Ship. 🚀</h1>;
}
function HomePage() {
  return <div></div>;
}

ReactDOM.render(<Header />, app);

<Header> 컴포넌트를 <HomPage> 컴포넌트 안에 중첩시키자:

function Header() {
  return <h1>Develop. Preview. Ship. 🚀</h1>;
}

function HomePage() {
  return (
    <div>
      {/* Nesting the Header component */}
      <Header />
    </div>
  );
}

ReactDOM.render(<Header />, app);

Component Trees

이 방식으로 React 컴포넌트들을 계속 중첩시켜서 컴포넌트 트리를 만들 수 있다.

예를들어, 상위의 HomePage 컴포넌트는 Header, Article, Footer 컴포넌트를 가질 수 있다. 그리고 각각의 컴포넌트들은 자신만의 자식 컴포넌트들을 가질 수 있고, 계속 이렇게 이어나갈 수 있다. 예를들어, Header 컴포넌트는 Logo, Title, Navigation 컴포넌트를 가질 수 있다.

이 모듈 형식은 앱의 다른 부분에서 컴포넌트를 재사용할 수 있게 한다.

당신의 프로젝트에서, <HomePage>가 가장 상위 컴포넌트이기 때문에, 이를 ReactDOM.render() 메소드에 넘길 수 있다.

function Header() {
  return <h1>Develop. Preview. Ship. 🚀</h1>;
}

function HomePage() {
  return (
    <div>
      <Header />
    </div>
  );
}

ReactDOM.render(<HomePage />, app);

Displaying Data with Props

지금까지, <Header/> 컴포넌트를 재사용하려면 매번 동일한 컨텐츠를 표시해야만 했다.

function Header() {
  return <h1>Develop. Preview. Ship. 🚀</h1>;
}

function HomePage() {
  return (
    <div>
      <Header />
      <Header />
    </div>
  );
}

하지만 다른 텍스트를 넘기고 싶거나, 외부에서 데이터를 가져와서 미리 보여줄 정보를 알지 못하는 경우는 어떻게 해야할까?

일반 HTML 요소에는 요소의 동작을 변경하는 정보를 전달할 수 있는 속성들을 가진다. 예를들어, <img> 요소의 src 속성을 바꾸면 보여지는 이미지가 바뀐다. href 속성의 <a> 태그를 바꾸면 목적지 링크가 바뀐다.

같은 방식으로, React 컴포넌트에게 속성처럼 정보 일부를 넘길 수 있다. 이를 props라 부른다.

JavaScript 함수와 비슷하게, 컴포넌트의 동작이나 화면에 렌더링될때 어떻게 시각적으로 보일지를 변경하는 커스텀 인자들(또는 props)를 받는 컴포넌트를 디자인할 수 있다. 그리고 이 props들을 부모 컴포넌트에서 자식 컴포넌트들로 내려보낼 수 있다.

| Note: React에서, 데이터는 컴포넌트 트리를 따라 내려간다. 이를 단방향 데이터 흐름이라 한다. 다음 섹션에서 다룰 state 역시 props처럼 부모에서 자식 컴포넌트로 내려갈 수 있다.

Using props

HomePage 컴포넌트에서, HTML 속성을 전달한 것 처럼 Header 컴포넌트에게 커스텀 title prop을 전달할 수 있다.

// function Header() {
//   return <h1>Develop. Preview. Ship. 🚀</h1>
// }

function HomePage() {
  return (
    <div>
      <Header title="React 💙" />
    </div>
  );
}

// ReactDOM.render(<HomePage />, app)

그리고 자식 컴포넌트인 Header함수 파라미터로 이 prop을 받을 수 있다.

function Header(props) {
//   return <h1>Develop. Preview. Ship. 🚀</h1>
// }

// function HomePage() {
//   return (
//     <div>
//       <Header title="React 💙" />
//     </div>
//   )
// }

// ReactDOM.render(<HomePage />, app)

prop을 console.log() 해보면, title 프로퍼티를 가지는 객체임을 확인할 수 있다.

function Header(props) {
    console.log(props) // { title: "React 💙" }
//   return <h1>React 💙</h1>
// }

// function HomePage() {
//   return (
//     <div>
//       <Header title="React 💙" />
//     </div>
//   )
// }

// ReactDOM.render(<HomePage />, app)

props가 객체이기 때문에, 함수 파라미터 안에서 객체 비구조화할당을 사용하여 props 값의 이름을 명시적으로 지정할 수 있다.

function Header({ title }) {
    console.log(title) // "React 💙"
//  return <h1>React 💙</h1>
// }

// function HomePage() {
//   return (
//     <div>
//       <Header title="React 💙" />
//     </div>
//   )
// }

// ReactDOM.render(<HomePage />, app)

이제 <h1> 태그의 내용을 title 변수로 교체할 수 있다.

function Header({ title }) {
  console.log(title);
  return <h1>title</h1>;
}

이 프로젝트를 브라우저에서 열어보면, "title" 단어가 실제로 표시되고 있음을 확인할 수 있다. React는 당신이 DOM에 일반 텍스트 문자열을 렌더링하고 싶어한다고 생각하기 때문이다.

React에게 이것이 JavaScript 변수임을 알려줄 방법이 필요하다.

Using Variables in JSX

정의한 변수를 사용하기 위해선, JSX 마크업 안에 표준 JavaScript를 작성할 수 있게 해주는 특별한 문법인 중괄호 {}를 사용할 수 있다.

// function Header({title}) {
//  console.log(title)
return <h1>{title}</h1>;
// }

중괄호를 "JSX land"에서 "JavaScript land"로 들어가게 해주는 방법이라고 생각하면 된다. 아무 JavaScript 표현식(단일 값으로 평가되는 것)이든지 중괄호 안에 넣을 수 있다. 예를들어:

  1. 점 표기법을 사용하는 객체 프로퍼티
function Header(props) {
  return <h1>{props.title}</h1>;
}
  1. 템플릿 리터럴
function Header({ title }) {
  return <h1>{`Cool ${title}`}</h1>;
}
  1. 함수의 반환값
function createTitle(title) {
  if (title) {
    return title;
  } else {
    return 'Default title';
  }
}

function Header({ title }) {
  return <h1>{createTitle(title)}</h1>;
}
  1. 또는 삼항연산자
function Header({ title }) {
  return <h1>{title ? title : 'Default Title'}</h1>;
}

title prop에 어떠한 문자열이든지 넘겨줄 수 있고, 심지어 컴포넌트에서 삼항연산자를 사용하여 default 케이스를 처리하고 있으면 title prop에 아무것도 넘겨주지 않아도 된다:

function Header({ title }) {
  return <h1>{title ? title : 'Default title'}</h1>;
}

function HomePage() {
  return (
    <div>
      <Header />
    </div>
  );
}

우리의 컴포넌트는 이제 애플리케이션의 다른 부분에서도 재사용할 수 있도록 일반적인 title prop을 받고 있다. 해야할것은 오직 title을 바꾸는 것 뿐이다:

function HomePage() {
  return (
    <div>
      <Header title="React 💙" />
      <Header title="A new title" />
    </div>
  );
}

Iterating through lists

리스트처럼 보여줄 필요가 있는 데이터를 가지는 경우가 일반적이다. 배열 메소드를 사용하여 데이터를 조작하거나 스타일은 동일하지만 다른 정보를 가진 UI 요소들을 생성할 수 있다.

| Note: React는 data fetching에 있어서 독단적이지 않다. 즉 필요에 따라 최선의 솔루션을 선택할 수 있다. 추후에, Next.js에서 data fetching 옵션들에 대해 이야기할것이다. 하지만 지금은, 데이터를 표시하기 위해 단순한 배열을 사용하자.

<HomePage> 컴포넌트에 이름 배열을 추가하자:

function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];

  return (
    <div>
      <Header title="Develop. Preview. Ship. 🚀" />
    </div>
  );
}

배열을 반복하기 위해 array.map() 메소드를 사용하고, 이름을 리스트 아이템과 매핑하기 위해 화살표 함수를 사용한다:

function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];

  return (
    <div>
      <Header title="Develop. Preview. Ship. 🚀" />
      <ul>
        {names.map((name) => (
          <li>{name}</li>
        ))}
      </ul>
    </div>
  );
}

"JavaScript"와 "JSX" land에서 중괄호를 사용하여 안팎으로 코드를 작성한것을 주의해라.

이 코드를 실행하면, React는 key prop이 없다는 경고를 표시할 것이다. React는 DOM을 업데이트 하는 요소가 무엇인지 알기 위한 유니크한 아이템 식별자를 필요로 하기 때문이다.

지금은 이름이 고유하기 때문에 용할 수 있지만, ID같은 유니크함이 보장된 무언가를 사용하는 것을 추천한다.

function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];

  return (
    <div>
      <Header title="Develop. Preview. Ship. 🚀" />
      <ul>
        {names.map((name) => (
          <li key={name}>{name}</li>
        ))}
      </ul>
    </div>
  );
}

Adding Interactivity with State

React가 어떻게 state와 이벤트 핸들러를 통해 인터렉션을 추가하는지 알아보자.

예시로, HomePage 컴포넌트 안에 좋아요 버튼을 만들어보자. 먼저, return() 문 안에 버튼 요소를 추가하자.

function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];

  return (
    <div>
      <Header title="Develop. Preview. Ship. 🚀" />
      <ul>
        {names.map((name) => (
          <li key={name}>{name}</li>
        ))}
      </ul>

      <button>Like</button>
    </div>
  );
}

Listening to Events

버튼을 클릭했을때 무언갈 하게 만들기 위해선, onClick 이벤트를 이용할 수 있다.

function HomePage() {
  // ...
  return (
    <div>
      {/* ... */}
      <button onClick={}>Like</button>
    </div>
  );
}

React에서 이벤트 이름은 camelCase이다. onClick 이벤트는 유저 인터렉션에 응답하기 위해 사용할 수 있는 다양한 이벤트 중 하나이다. 예를들어, 인풋 필드에서 onChange 를 사용하거나 폼에서 onSubmit을 사용할 수 있다.

Handling Events

언제든 이벤트가 발생했을때 이를 '처리'할 수 있는 함수를 정의할 수 있다. return 문 이전에 handleClick() 함수를 만들자.

function HomePage() {
  // ...

  function handleClick() {
    console.log("increment like count")
  }

  return (
    <div>
      {/* ... */}
      <button onClick={}>Like</button>
    </div>
     )
   }  

이제, onClick 이벤트가 발생했을때 handleClick 함수를 호출할 수 있다.

function HomePage() {
 //    ...
 function handleClick() {
   console.log('increment like count');
 }

 return (
   <div>
     {/* ... */}
     <button onClick={handleClick}>Like</button>
   </div>
 );

State and Hooks

React는 hook이라 부르는 함수 집합을 가지고 있다. hook은 컴포넌트에 state와 같은 추가적인 로직을 추가할 수 있게 해준다. state는 주로 유저 인터렉션에 의해, 시간이 지나면서 변하는 UI안의 모든 정보라고 생각하면 된다.

유저가 버튼을 몇번 클릭했는지 횟수를 저장하고 증가시키는데 state를 사용할 수 있다. state를 관리하기 위한 React hook은 useState()라 부른다.

function HomePage() {
  React.useState();
}

useState()는 배열을 반환하고, 배열 비구조화를 통해 컴포넌트 안에서 해당 배열값에 접근하고 사용할 수 있다.

function HomePage() {
  const [] = React.useState();

  // ...
}

배열의 첫번째 아이템은 state value이며 아무 이름이나 지정할 수 있다. 설명이 포함된 이름을 지정하는게 좋다.

function HomePage() {
  const [likes] = React.useState();

  // ...
}

배열의 두번째 아이템은 value를 update하는 함수다. update 함수도 아무렇게나 이름붙일 수 있지만, 업데이트하려는 상태 변수 이름 앞에 접두사로 set을 붙이는게 일반적이다.

function HomePage() {
  const [likes, setLikes] = React.useState();

  // ...
}

likes 상태의 초기값을 추가할수도 있다.

function HomePage() {
  const [likes, setLikes] = React.useState(0);
}

이제, 컴포넌트 안에서 state 변수를 사용하여 초기 상태가 동작하는지 확인할 수 있다.

function HomePage() {
  // ...
  const [likes, setLikes] = React.useState(0);

  return (
    // ...
    <button onClick={handleClick}>Like({likes})</button>
  );
}

마지막으로, HomePage 컴포넌트 안에서 setLikes 상태 업데이트 함수를 호출할 수 있다. 사전에 정의한 handleClick() 함수 안에 추가하자.

function HomePage() {
  // ...
  const [likes, setLikes] = React.useState(0);

  function handleClick() {
    setLikes(likes + 1);
  }

  return (
    <div>
      {/* ... */}
      <button onClick={handleClick}>Likes ({likes})</button>
    </div>
  );
}

버튼을 클릭하면 현재 좋아요수 + 1을 단일 인자로 받는 setLieks 상태 업데이트 함수인 handleClick 함수가 호출된다.

| Note: 함수 파라미터처럼 컴포넌트에 전달되는 props와 달리, state는 컴포넌트 안에서 초기화되고 저장된다. 자식 컴포넌트에게 props로 state를 전달할 수 있지만, state를 업데이트하는 로직은 최초에 상태가 생성된 컴포넌트 내에 유지되어야 한다.

How to Continue Learning React

지금까지 3가지 React 핵심 개념 : component, prop, state에 대해 소개했다. 이들에 대해 탄탄한 기초를 가지는것이 React 애플리케이션을 개발하는데 도움이 될 것이다. 자신감이 생기면, 다른 주제들을 확인해라.

  • React가 렌더링을 처리하는 방법과 ref를 사용하는
  • state 관리 방법
  • 깊게 중첩된 데이터에 대해 context를 사용하는 방법
  • useEffect()와 같은 React API hook을 사용하는 방법

React Resources

수년간에 걸쳐, React를 학습하고자 하는 개발자들을 돕기 위한 많은 강의, 영상, 아티클들이 만들어졌다. 당신의 학습 스타일에 맞는 리소스를 추천하긴 힘들지만, 주제를 연습하는데 도움이 되는 대화형 샌드박스가 포함된 React 공식문서는 좋은 자료이다.

React를 배우는 가장 좋은 방법은 만드는 것이다. 기존 웹사이트에 작은 컴포넌트를 추가하기 위해 지금까지 배운 것과 <script> 태그를 이용하여 React를 점진적으로 채택할 수 있다. 하지만, 많은 개발자들은 React로 전체 프런트엔드 프로젝트를 바로 시작하고 작성할 수 있을 만큼 사용자 및 개발자 경험이 가치가 있음을 발견했다.

From React to Next.js

React는 UI 개발에 뛰어나지만, 해당 UI가 완벽하게 작동하는 확장가능한 애플리케이션으로 독립적으로 구축하기 위해선 약간의 작업이 필요하다. 좋은 소식은 Next.js에 React 애플리케이션을 개발하는데 도움이 되는 많은 설정, 구성 및 추가적인 기능들이 있다는 점이다.

다음으로, React에서 Next.js로 예제를 마이그레이션하고, Next.js가 어떻게 작동하는지 이야기하고, Next.js의 심화 기능을 배우는 데 도움이 되는 몇 가지 웹 개발 개념을 소개한다.

From React to Next.js

지난 강의에서, React를 시작하는 방법에 대해서 이야기했다. 아래는 우리의 최종 코드다. 만약 여기서 시작한다면, 아래 코드를 코드 에디터의 index.html 에 붙여넣어라.

<html>
  <body>
    <div id="app"></div>

    <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

    <script type="text/jsx">
      const app = document.getElementById("app")

      function Header({ title }) {
        return <h1>{title ? title : "Default title"}</h1>
      }

      function HomePage() {
        const names = ["Ada Lovelace", "Grace Hopper", "Margaret Hamilton"]

        const [likes, setLikes] = React.useState(0)

        function handleClick() {
          setLikes(likes + 1)
        }

        return (
          <div>
            <Header title="Develop. Preview. Ship. 🚀" />
            <ul>
              {names.map((name) => (
                <li key={name}>{name}</li>
              ))}
            </ul>

            <button onClick={handleClick}>Like ({likes})</button>
          </div>
        )
      }

      ReactDOM.render(<HomePage />, app)
    </script>
  </body>
</html>

이제 간단한 React 앱을 Next.js로 어떻게 옮길 수 있는지 알아보자.

Getting Started with Next.js

프로젝트에 Next.js를 추가하려면, 더이상 unpkg.com에서 reactreact-dom script들을 불러올 필요가 없다. 대신, 노드 패키지 매니저 : npm을 이용하여 로컬에 패키지들을 다운받을 수 있다.

| Note: 컴퓨터에 Node.js를 설치해야한다(최소 요구 버전), 여기서 다운받을 수 있다.

그렇게 하기 위해서, 빈 객체 {}로 이루어진 package.json 파일을 만들어라.

//package.json
{
}

터미널에, npm install react react-dom next를 실행해라. 설치가 완료되면, package.json 파일 안에 나열된 프로젝트의 의존성들을 확인할 수 있다.

// package.json
{
  "dependencies": {
    "next": "^12.1.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  }
}

또한 실제 의존성 파일들을 포함하고 있는 새로운 node_modules 폴더를 확인할 수 있다.

index.html 파일로 돌아와서, 아래 코드들을 삭제할 수 있다:
1. NPM으로 설치한 react, react-dom 스크립트
2. Next.js가 만들어줄 <html>, <body> 태그
3. app 요소와 상호작용하는 코드와 ReactDom.render() 메서드
4. Next.js가 JSX를 브라우저가 이해하는 유효한 자바스크립트로 변환하는 컴파일러를 가지고 있기 때문에 Babel script
5. <script type="text/jsx"> 태그
6. React.useState(0) 함수의 React. 부분

위에 해당하는 줄을 지우고, 파일 상단에 import {useState} from 'react를 추가해라. 이제 코드는 이렇게 생겼을것이다:

// index.html
import { useState } from 'react';
function Header({ title }) {
  return <h1>{title ? title : 'Default title'}</h1>;
}

function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];

  const [likes, setLikes] = useState(0);

  function handleClick() {
    setLikes(likes + 1);
  }

  return (
    <div>
      <Header title="Develop. Preview. Ship. 🚀" />
      <ul>
        {names.map((name) => (
          <li key={name}>{name}</li>
        ))}
      </ul>

      <button onClick={handleClick}>Like ({likes})</button>
    </div>
  );
}

HTML파일에 남아있는 유일한 코드는 JSX이기 때문에, 파일 형식을 .html에서 .js.jsx로 바꿔야 한다.

이제, 완전히 Next.js 앱으로 전환하기 위해 해야할 3가지 일이 남아있다:
1. index.js 파일을 새로운 pages 폴더로 옮기기 (자세한 내용은 추후 설명)
2. Next.js가 이 페이지에서 메인 컴포넌트로서 렌더링해야할 컴포넌트를 구분할 수 있도록 메인 React 컴포넌트에 default export 추가하기

   // ...
   export default function HomePage() {
   //  ...

     ```
 3. 개발중에 Next.js 개발 서버를 실행하기 위해 `package.json` 파일에 script 추가
 ```json
 // package.json
   {
    "scripts": {
        "dev": "next dev"
    },
     // "dependencies": {
     //   "next": "^11.1.0",
     //   "react": "^17.0.2",
     //   "react-dom": "^17.0.2"
     // }
   }

Running the development server

잘 작동하는지 확인하기 위해서, 터미널에서 npm run dev를 실행하고 브라우저에서 localhost:3000으로 이동하여 앱을 확인할 수 있다. 코드에 작은 변화를 주고 저장해보자.

파일을 저장하면, 브라우저가 변화를 반영하기 위해 자동으로 업데이트되는 것을 확인할 수 있다.

이 기능을 Fast Refresh라고 부른다. 수정사항에 대해 즉각적인 피드백을 제공하고 Next.js에 의해 미리 구성되어 제공된다.

요약하자면, 우리의 코드는 아래에서:

<html>
  <body>
    <div id="app"></div>

    <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

    <script type="text/jsx">
      const app = document.getElementById("app")

      function Header({ title }) {
        return <h1>{title ? title : "Default title"}</h1>
      }

      function HomePage() {
        const names = ["Ada Lovelace", "Grace Hopper", "Margaret Hamilton"]
        const [likes, setLikes] = React.useState(0)

        function handleClick() {
          setLikes(likes + 1)
        }

        return (
          <div>
            <Header title="Develop. Preview. Ship. 🚀" />
            <ul>
              {names.map((name) => (
                <li key={name}>{name}</li>
              ))}
            </ul>

            <button onClick={handleClick}>Like ({likes})</button>
          </div>
        )
      }

      ReactDOM.render(<HomePage />, app)
    </script>
  </body>
</html>

...이렇게 바뀌었다:

import { useState } from 'react';

function Header({ title }) {
 return <h1>{title ? title : 'Default title'}</h1>;
}

export default function HomePage() {
 const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];
 const [likes, setLikes] = useState(0);

 function handleClick() {
   setLikes(likes + 1);
 }

 return (
   <div>
     <Header title="Develop. Preview. Ship. 🚀" />
     <ul>
       {names.map((name) => (
         <li key={name}>{name}</li>
       ))}
     </ul>

     <button onClick={handleClick}>Like ({likes})</button>
   </div>
 );
}

표면적으로, 코드는 약간 줄었지만 무언가를 강조하는데 도움이된다 : React는 현대 인터렉티브 UI를 만들기 위해 필수적인 기본요소들을 제공하는 라이브러리이다. 하지만 개발한 UI를 애플리케이션으로 결합하는데는 여전히 약간의 작업이 필요하다.

마이그레이션을 살펴보면, 이미 Next.js 사용의 이점을 느끼고 있을 것이다. 더 이상 생각할 필요가 없는 복잡한 구성 도구인 babel secript를 제거했다. 또한 Next.js에서 기대할 수 있는 많은 개발자 경험 기능 중 하나인 Fast Refresh가 실행되는 것을 확인했다.

Next Steps

첫번째 Next.js 애플리케이션을 만든 걸 축하한다!

요약하자면, React와 Next.js의 기초지식에 대해 알아봤고 단순한 React 애플리케이션을 Next.js 애플리케이션으로 마이그레이션 해봤다.

이제 Next.js 여행의 다음 단계를 선택할 수 있다:
1. creating your first app을 통해 어떻게 Next.js를 사용하는지 배워라 - 이 강의는 Next.js의 핵심 기능에 대해 소개하고 좀 더 복잡한 프로젝트를 만들어보면서 연습할 수 있다.
2. 이 강의를 계속하면서 Next.js가 어떻게 동작하는지 더 깊게 알아보자.

다음 강의에서는 몇 가지 관련된 웹 개발 개념을 소개하면서 Next.js가 어떻게 동작하는지 알아본다. 이러한 개념에 익숙해지면 기초를 넓히고 심화 Next.js 기능을 더 쉽게 배울 수 있다.

0개의 댓글