리알못 React: 0. 개발환경 구축 및 JavaScript ES6 Refresher

Table of Content

이 글은 Code with Mosh의 Mastering React 과정을 공부하며 정리한 글입니다. 리알못이라 이상하거나 틀린 내용이 있을 것입니다…

개발환경 구축

NPM 설치

create-react-app 다운로드

npm을 사용하여 create-react-app 패키지를 다운받습니다. 터미널에서 실행할 명령어는 npm i -g create-react-app 입니다. permission 오류가 발생하면 sudo npm i -g create-react-app 명령어를 실행합니다.

사용한 파라미터는 다음과 같습니다.

  • i: install
  • -g: global
ing-yeo-MacBook-Pro% npm i -g create-react-app ## create-react-app 다운로드
Password:
/usr/local/bin/create-react-app -> /usr/local/lib/node_modules/create-react-app/index.js
+ create-react-app@3.0.1
updated 1 package in 2.706s

위의 명령어를 실행하면 최신 버전의 create-react-app 패키지를 다운받습니다. 특정 버전을 다운받으려면 골뱅이 기호(@) 뒤에 버전을 명시해주시면 됩니다. 예를 들어 1.5.2 버전을 다운받고자 한다면 npm i -g create-react-app@1.5.2 명령어를 사용하면 됩니다.

create-react-app 설치

React 프로젝트 디렉토리를 생성한 후 그곳에 create-react-app을 설치합니다. 명령어는 다음과 같습니다.

ing-yeo-MacBook-Pro% mkdir react-test ## React 프로젝트 디렉토리 생성
ing-yeo-MacBook-Pro% cd react-test ## 생성된 프로젝트 디렉토리로 이동
ing-yeo-MacBook-Pro% create-react-app . ## 현재 위치한 디렉토리에 create-react-app 설치

create-react-app 실행

create-react-app으로 개발한 앱을 브라우저를 통해 실행하려면 React 프로젝트가 위치한 곳에서 npm start 명령어를 사용합니다. 명령어 실행 후 자동으로 웹 브라우저에 React 앱이 실행됩니다. 중지하려면 Control+C 키를 입력합니다.

ing-yeo-MacBook-Pro% npm start ## create-react-app 실행

> react-test@0.1.0 start /Users/ing-yeo/Documents/React/react-test
> react-scripts start

Starting the development server...
Compiled successfully!
You can now view react-test in the browser.

  Local:            http://localhost:3000/
  On Your Network:  http://192.168.0.15:3000/

Note that the development build is not optimized.
To create a production build, use npm run build.

소스 코드 편집기 설치

코딩을 위한 소스 코드 편집기를 설치합니다. 저는 Visual Studio Code(VS Code)를 설치하여 사용중입니다.

참고로, VS Code에서 Snippet 플러그인을 사용하면 코드를 편하게 작성할 수 있습니다. 저는 Simple React Snippets라는 플러그인을 사용하고 있습니다. 이 플러그인으로 주로 사용하는 키워드는 다음과 같습니다.

  • imrc 키워드: React 및 { Component } import 코드 생성
  • cc: 클래스 컴포넌트 기본 골격 코드 생성

프로젝트 내 파일 구성

node_module 폴더

node_module 폴더에는 React 및 서드 파티 라이브러리 등이 저장되어 있습니다.

  • Babel: JSX를 JS로 변환하는 Modern JavaScript Compiler

public 폴더

public 폴더에는 파비콘, 메타 데이터 등이 저장되어 있습니다.

  • index.html: 메타 데이터 모음
    • <div id="root">: React 앱의 컨테이너

src 폴더

src 폴더에는 소스코드가 저장됩니다.

  • App.js: 앱 메인화면
  • index.js: 앱의 진입점
  • logo.svg: 앱의 로고
  • serviceWorker.js: 자동 생성되는 코드. 수정하면 안 됨!

Custom Configs

React 프로젝트 루트 디렉토리에 있는 package.json 파일을 열어보면 앱의 이름, 버전, 의존성 및 스크립트(start, build, test, eject)를 확인할 수 있습니다.

npm run eject 명령어는 npm 패키지 내에 포함된 설정파일과 스크립트를 직접 수정할 수 있도록 추출(eject)해주는 명령어입니다. 고급 개발자가 아니라면 실행하지 않아야 할 것입니다.

Hello World! 띄워보기

Hello World를 띄우기 전에 React 프로젝트의 결과물이 어떻게 보여지는지 알아봅시다.

index.js

src 폴더에 있는 index.js 파일을 열어보면
ReactDOM.render(<App />, document.getElementById('root'));
라는 코드가 있습니다. 이 코드는 id가 root인 요소, 즉 public/index.html 파일 내의 <div id="root">를 렌더링합니다. 더불어 App 컴포넌트도 렌더링합니다.

App 컴포넌트

App.js 파일을 열어보면 React 로고를 띄우는 코드가 있을 것입니다. 이 코드를 모두 지운 후 다음과 같이 구현해줍니다.

import React, { Component } from 'react';

class App extends Component {
  render() {
    return ( <h1>Hello World!</h1> );
  }
}

export default App;

위 코드는 App 컴포넌트에서 Hello World! 라는 제목의 문구를 반환하도록 합니다. 이렇게 구현된 App 컴포넌트는 index.js 파일의 render() 메소드에 의해 렌더링되어 보여지게 됩니다.

JavaScript ES6 Refresher

var, let 그리고 const

  • var로 선언된 변수는 선언된 코드블록 외부에서도 접근이 가능합니다.
  • let으로 선언된 변수는 선언된 코드블록 내부에서만 접근이 가능합니다.
  • const로 선언된 상수는 코드블록 내부에서만 접근이 가능합니다. 상수이므로 값을 변경할 수 없습니다. (read-only)
function sayHello() {
  for (var i = 0; i < 5; i++) {
    console.log(i);
  }
  console.log(i); // 에러 발생 X (var는 선언된 코드블록 외부에서도 접근 가능)
}
sayHello();
function sayHello() {
  for (let i = 0; i < 5; i++) {
    console.log(i);
  }
  console.log(i); // 에러 발생 O (let은 선언된 코드블록 내부에서만 접근 가능)
}
sayHello();
const x = 1;
x = 2; // 에러 발생 O (const는 read-only)

객체(Object) 생성 및 제어

// 객체 생성
const person = {
  name: "ing-yeo",
  walk: function() {}, // 함수 선언
  talk() {} // 함수 선언 시 function()을 제외해도 됨
};

// 객체 접근
const targetMember = "name";
person[targetMember] = "React";
person['name'] = "React"
person.talk();

this 키워드와 bind() 메소드

  • this 키워드는 현재 객체에 대한 참조를 위해 사용되며 함수가 어떻게 호출되는지에 따라 결정됩니다.
  • 객체 외부에서 this 키워드가 호출된다면 전역객체(브라우저 내 window object)를 참조하게 됩니다. 이 때 bind() 메소드를 사용하면 항상 특정 객체를 참조하도록 할 수 있습니다.
const person = {
  name: "ing-yeo",
  walk() {
    console.log(this); // 현재 객체(person 객체)에 대한 로그 출력
  }
};

const walk1 = person.walk;
console.log(walk1); // 현재 객체(person.walk() 메소드)에 대한 로그 출력
walk1(); // 출력결과: undefined 또는 window 객체 정보 출력

const walk2 = person.walk.bind(person);
walk2(); // 출력결과: bind() 메소드에 의해 person 객체 정보 출력

화살표 함수

  • 화살표 함수를 사용하면 간결하게 함수를 선언할 수 있습니다. Array.map() 또는 Array.filter() 등의 함수 내에서 조건을 걸 때 유용하게 사용할 수도 있습니다.
// 기존 JavaScript 코드
const square1 = function(number) {
  return number * number;
};

// ECMA Script 6에서의 코드
const square2 = number => number * number; // return 키워드 생략 가능
console.log(square2(5));

// filter() 함수 사용 시 화살표 함수를 유용하게 사용할 수 있음
// 아래 activeJobs1과 activeJobs2는 모두 똑같이 동작
const jobs = [
  { id: 1, isActive: true },
  { id: 2, isActive: true },
  { id: 3, isActive: false }
];

const activeJobs1 = jobs.filter(function(job) {
  return job.isActive;
});
const activeJobs2 = jobs.filter(job => job.isActive); // isActive가 true인 객체만 남김

console.log(activeJobs1);
console.log(activeJobs2);
  • 화살표 함수는 this 키워드를 재결합(rebind)하지 않으므로 재결합돼버리는 콜백 함수를 사용할 때 유용합니다.
const person = {
  talk1() {
    console.log("talk1", this); // person 객체 로그 출력
  },

  talk2() {
    setTimeout(function() {
      console.log("talk2", this); // window 객체 로그 출력. 콜백 함수는 어떤 객체의 부분도 아님. rebind 되어버림?
    }, 1000);
  },

  talk3() {
    setTimeout(() => {
      console.log("talk3", this); // person 객체 로그 출력. 화살표 함수는 rebind되지 않으므로 기존 person 객체 유지.
    }, 1000);
  }
};

person.talk1();
person.talk2();
person.talk3();

Array.map() 함수

Array.map() 함수는 배열의 모든 요소를 특정 기준에 맞춰 일괄적으로 변형하기 위해 사용합니다. 기존 배열값을 수정하는 것이 아닌 반환을 하므로 주의해야 합니다.

const color = ["red", "green", "blue"];

// 아래 코드는 모두 똑같이 작동
const items1 = color.map(function(color) {
  return "<li>" + color + "</li>";
});
const items2 = color.map(color => "<li>" + color + "</li>");
const items3 = color.map(color => "<li>${color}</li>"); // 정규표현식 같은 걸 쓸 수 있다는데... 나는 안되네;;;

console.log(items1);
console.log(items2);
console.log(items3);

// 참고: foreach 사용 예
items3.foreach(item => console.log(item));

구조 분해 할당 문법(Object Destructing)

객체에서 값을 꺼내올 때 구조 분해 할당 문법을 사용하면 코드를 간결하게 작성할 수 있습니다.

const address = {
  street: "11st",
  city: "Seoul",
  country: "Korea"
};

// 이런 코드는 너무 반복적
// const street = address.street;
// const city = address.city;
// const country = address.country;

// 이 코드는 위 세 코드와 동일함
const { street, city, country } = address;

// 다른 이름을 주고 싶다면 콜론(:) 사용
const { street: st } = address;

console.log(street);
console.log(st);
console.log(city);
console.log(country);

Spread Operator

Spread Operator(…)는 해당 배열의 모든 요소를 가리킵니다. 이를 이용하여 배열을 쉽게 편집할 수 있습니다.

const first = [1, 2, 3];
const second = [4, 5, 6];
const combined1 = first.concat(second);
const combined2 = [...first, ...second];
const combined3 = [...first, "a", 100, ...second, "b"];
console.log(combined1);
console.log(combined2);
console.log(combined3);
const first = { name: "ing-yeo" };
const second = { job: "ing-yeo ingan" };
const combined = { ...first, ...second, location: "Korea" };
console.log(combined);

클래스

class Person {
  constructor(name) { this.name = name; }

  walk() { console.log("Walk"); }
}

class Teacher extends Person {
  // 상속받는 클래스에서 생성자 미 구현 시 자동으로 생성자도 상속받음
  constructor(name, degree) {
    super(name); // 상위 클래스 생성자 호출하지 않으면 에러 발생
    this.degree = degree;
  }

  teach() { console.log("Teach"); }
}

const person = new Person("ing-yeo");
person.walk();

const teacher = new Teacher();
teacher.walk();

모듈

위의 클래스 코드를 여러 파일(모듈)로 나누기

  • Person.js
// 클래스는 기본적으로 접근 설정이 private이므로
// export 키워드를 사용하여 외부에서 이 클래스를 참조할 수 있도록 선언
export class Person {
  constructor(name) { this.name = name; }

  walk() { console.log("Walk"); }
}
  • Teacher.js
import { Person } from "./Person";

export class Teacher extends Person {
  // 상속받는 클래스에서 생성자 미 구현 시 자동으로 생성자도 상속받음
  constructor(name, degree) {
    super(name); // 상위 클래스 생성자 호출하지 않으면 에러 발생
    this.degree = degree;
  }

  teach() { console.log("Teach"); }
}
  • test.js
import { Teacher } from "./Teacher";

const teacher = new Teacher("ing-yeo", "A+");
teacher.teach();

Named and Default Exports

  • named export는 한 모듈당 여러 값을 export 할 수 있습니다.
  • default export는 한 모듈당 하나의 값만 export 할 수 있습니다.
  • named export 및 default export된 값을 가져오는 코드는 다음과 같습니다.
// Default Export -> import ... from "./Path"
// Named Export -> import { ... } from "./Path"

댓글 남기기