본문 바로가기
Today I learned

[react] 1 주차 react를 page 방식으로 개발해보자. (1)

by soheemon 2020. 1. 11.

* 수업진행

* 데모 사이트

 

환경설정

VC를 쓰고 WebStorm을 사용한다. WebStorm은 학교메일이 있으면 1년 무료

 

node 설치

node -v

 

git 설치 

git -version

 

webstorm 설치

react getting-started

 

- React는 UI에 특화된 라이브러리다. 내가 함수를 가져다 쓰면 되는것임.

 

예제
<html><head>
    <meta charset="utf-8">
    <title>Scoreboard</title>
    <link href="./app.css" rel="stylesheet">
</head>

<body>
  <div id="root"><h1 title="this is a title" id="main-title">myfirst React Element</h1></div>
  <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin=""></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin=""></script>
  <script src="./app.js"></script>

</body>
</html>

첫번째 스크립트는 - react 코어 라이브러리 실행을 하면 react라는 글로벌 변수가 생성된다. JQuery로 예를 들자면 $가 전역변수로 생성되는것과 마찬가지다.

native 스크립트는 -  dom을 랜더링해주는 것 안드로이드 native랑 IOS native로 변환하는 스크립트. ReactDom이라는 글로벌 변수가 생성된다. 

세번째 - 사용자가 사용하는 스크립트

 

순서가 중요하다. 의존성이 있다. 예를들어 JQuery UI와 JQuery라이브러리가 있으면 순서에 맞게 작성해야 하는데 react는 그럴필요가 없다는것 같다.

 

index.html을 실행하면 웹스톰이 웹서버를 띄워서 실행한다.

CDN으로 선언하고 로컬에 파일이 없으면 런타임에 가져오게 된다.

함수 정보를 가져오기 위해 로컬에서도 라이브러리를 다운로드 받도록 하자.

@Type Script로 맵핑이 되어있다는 의미이다.

TypeScript 많이쓴다. Node랑 TypeScript를 쓴다.

TypeScript는 변수명이 앞에 온다.

변수명: 타입

예) a: string

 

type: html 태그명이 들어간다. 컴포넌트 클래스도 가능.(react function componenet 혹은 class component)

props?: html내부에 들어가는 속성에 해당한다.

변수명 ?(옵셔널 연산자.) => 변수명이 올수도 있고 안올수도 있다는 의미.  

Attributes => json 객체라고 보면 된다. 

...children => 두가지 의미를 가진다. 자식노드를 의미하는듯함. 3번째 부터 오는 파라미터를 얘가 다받게 된다. 

 

리턴타입은 React Element 로써 자바스크립트 객체이다. 리액트에서는 DOM을 직접 다루는게 아니라 DOM과 매핑된 자바스크립트 객체인 VirtualDom을 다룬다.

 

 두번째 세번째 파라메터로 전달한것이 모두 props로 저장되었다는것을 개발자 콘솔에서 확인해보자.

 

ctrl + q

코드

// 리턴타입 : ReactElement
const title = React.createElement(
    'h1',
    {id:'main-title', title: 'this is a title'},
    'myfirst React Element'
);

console.log(title);

//DOM을 이용해서 화면에 렌더링. react-dom.development를 import해서 쓸수있는거임
//두번째 파라미터는 컨테이너가 된다. title을 root라는 container에 넣은것임.!
ReactDOM.render(title, document.getElementById('root'));

결과

<html><head>
    <meta charset="utf-8">
    <title>Scoreboard</title>
    <link href="./app.css" rel="stylesheet">
</head>

<body>
  <div id="root"><h1 title="this is a title" id="main-title">myfirst React Element</h1></div>
  <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin=""></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin=""></script>
  <script src="./app.js"></script>

</body>
</html>

실제 DOM이 아니라 javascript객체이다. 그래서 성능이 좋다.

 

// 리턴타입 : ReactElement
const title = React.createElement(
    'h1',
    {id:'main-title', title: 'this is a title'},
    'myfirst React Element'
);
const desc = React.createElement(
    'p',
    null, //attribute가 없으니깐.
    'This is Discription'
    )

const header = React.createElement(
    'header',
    null,
    [title, desc] // ReactElement들이나 배열 올 수 있다.
)
console.log(title);

//DOM을 이용해서 화면에 렌더링. react-dom.development를 import해서 쓸수있는거임
//두번째 파라미터는 컨테이너가 된다. title을 root라는 container에 넣은것임.!
ReactDOM.render(header, document.getElementById('root'));

VirtualDom을 이해하기 위해 React.createElement를 사용한것입니다.

 

-react 렌더링

react는 실제 DOM 노드 즉, h1, div, span 같은 태그를 만들지 않는다. 대신에 DOM 노드를 서술하는 자바스크립트 객체를 만든다. createElement()를 사용하여 만든 자바스크립트 객체가 실제 DOM 노드로 렌더링 되는것일까? 그것은 render() 메서드가 하는 역할로서, createElement()로 만든 자바스크립트 객체를 실제 DOM으로 만들고 업데이트해주는 역할을 해준다.

react 는 실제 DOM을 다루는게 아니라 DOM에 매핑 되는 자바스크립트 객체를 다룬다는것이 Virtual DOM의 핵심이다. 만일 특정한 속성을 수정하게 되면 자바스크립트 객체에서 바뀐 부분을 찾는다. DOM에서 찾는게 아니라 메모리에 올라간 자바스크립트 객체에서 바뀐 비교 검색하기 때문에 실제 DOM을 다루는것보다 훨씬 빠르게 업데이트가 가능해준다.

 

처음에 한번 전체 DOM을 렌더링 한 이후에는 필요한 부분만 업데이트를 하게 된다. 메모리에 올라간 자바스크립트 객체에서 변경된 부분을 찾은 후 매핑되는 DOM 만 업데이트하는 식이다.

 

ReactDOM에서 render함수에는 rootComponent를 넣는다.

const h1 = React.createElement('h1', {title:'This is a title'},'My First React Element');

const p = React.createElement('p', null, 'This is a', React.createElement('strong', null, 'Description'));

ReactDOM.render([h1, p], document.getElementById('root'));

 

ES6

https://caniuse.com/

특정 태그나 js관련 문법이 각 브라우저에서 지원하는지 여부를 버전별로 확인 가능하다.

javascript 버전을 변경하여 사용할 수도 있다.

 

JSX 문법
  • JSX문법을 사용하면 문법이 훨씬 간소화가되는것을 확인할 수 있다. 
  • JSX의 도움으로, MarkDown을 이용해서 react 컴포넌트를 순수한 자바스크립트로 만들 수 있다.
  • JSX문법을 사용하기 위해서는 babel이라는 프리컴파일러가 필요하다. CDN으로 불러오도록 한다.

createElement() => JSX로의 변화 및 JSX 규칙

  1. 첫번째 파라메터 => 태그명으로 변경
  2. 두번째 파라메터 => 태그의 속성명으로 변경
  3. 세번째 이후 파라메터 => 모두 자식 노드로 변경
  4. class, for 의 속성명 => className, htmlFor로 변경
  5. 자바스크립트 표현식 => {} 를 사용 //약간 JAVA의 스크립트릿 느낌인듯?
  6. 반드시 닫는 태그가 있어야 한다.
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    <script type="text/babel" src="./app.js"></script>
Babel

https://babeljs.io/

Babel의 역할은 우리가 작성한 JSX코드를 React 코드로 변경해준다. - 결국 같다고 볼 수 있다. 으앙 넘 편해

try it out에서 테스트 해 볼 수 있다.

 

js시리즈를 공부하려면 ES6랑 TypeScript 공부를 해야 한다. 그래야 편함.

Emnet

Emnet이라는 플러그인을 사용하면 html 을 작성하기 무지 편함. 퍼블리싱에서 많이 씀.

예를 하나 들면 div > p.alignLeft 입력하고 Tab을 누르면 자동으로 html을 완성해준다. 

 

JSX 예제

기억합시다. JSX는 html이 아닙니다. JSX는 React Element를 반환합니다!

문법은 강제는 아니지만, 코딩컨벤션을 위해 앞 뒤로 ()를 붙여줍니다.

// html이 아니다! React Element이다. Babel사이트 가서 실행해보자.
const title = <h1 id="main-title" title="this is a Title"> My First React Element</h1>;
const desc = (
    <p>This is a Description</p>
);

//header 사이에 안만들어진 상태라면 JSX처럼 그냥 넣어도 되지만, 이미 만들어놓은 ReactElement를 사용할 수도 있다.
//이럴때는 JS 표현식 {}
const header = (
    <header>
        {title}
        {desc}
    </header>
);
//혹은 JS표현식 {} 안에 배열을 넣을수도 있다.{[title, desc]}
ReactDOM.render(header, document.getElementById('root'));

하지만 JSX하면 이렇게 잘 안씁니다. 밑에처럼 씁니다.

//class를 쓰면 className으로 쓰라고 웹스톰이 바꿔줌
const header = (
    <header>
        <h1 id="main-title" title="this is a Title"> My First React Element</h1>
        <p className={"h1"}>This is a Description</p>
    </header>
);

ReactDOM.render(header, document.getElementById('root'));

react에서 아직 지원이 안되는 태그들도 있습니다..

 

js 복습
//webStorm에서 js를 바로 실행 할 수도 있다...!
myName("Yan", "Fan");

// 아래는 함수 선언문(function definition)이다. 함수 표현식으로 바꾸시오.
// 함수 선언문과 함수 표현식의 차이점은 무엇인가? 표현식으로 바꾸면 에러가 나는가 안나는가?
function myName(first, last) {
    console.log(first + last);
}
호이스팅

변수, 함수들을 전부 테이블에 올리는것을 의미함.

함수 선언문의 경우 변수 객체가 만들어지는 과정에서 함수 선언 > 초기화 > 사용자 지정 값으로 초기화 된다.

따라서 실행단계에서 함수 선언문보다 함수 호출이 먼저 발생해도 정상적으로 실행된다.

 

함수 표현식의 경우에는 변수 호이스팅이 적용된다. 이것은 익명함수를 생성 후 변수에 익명함수를 할당하는 방식이다.

따라서 실행 단계에서 함수 표현식보다 함수 호출이 먼저 일어나면 에러가 발생한다.

 

 

//myName("Yan", "Fan"); // undefined 된다!

//익명함수의 형태가 된다. 함수표현식이라고 부른다.
//myName은 호이스팅이 되지만 할당문은 호이스팅이 일어나지 않는다.
//익명함수라서 호이스팅이 안되는건가..?
let myName = function (first, last) {
    console.log(first + last);
}

myName("Yan", "Fan"); //실행된다. 
// 1. 익명함수를 애로우펑션으로 전환 가능!
// 2. function을 생략하고 ())과 {} 사이에 =>(fatArrow)기호를 삽입한다.
// 만일 한문장이면 {}와 return을 생략 가능하다! let circleArea = (pi, r) => pi * r * r;
let circleArea = (pi, r) => {
    let area = pi * r * r;
    return area;
};
let result = circleArea(3.14, 3);

console.log(result); //실행 결과 "28.26"

 

Component개발 

JQuery UI로 만들어준 퍼블코드는 React로 작업하기가 어렵다.. 다시작업해야 한다고 생각 해야함...

JQuery는 알다시피, DOM을 동적으로 생성하기 때문..!

이 이미지를 어떻게 Component로 만들것인가..?

1. Component로 쪼갠다 > Component별로 따로 퍼블리싱 한다.

1-1. 어떤부분이 반복이 되는지 봐야한다. > 하나의 컴포넌트가 된다. > 잘게 쪼개면 확장성이 좋아진다. SRP 원칙

2. rootComponent를 만들어서 하위별로 Component를 구성하게 된다.

//Componenet의 종류
// 1) functionComponenet
// 2) ClassComponent => 뭔가 변하는게 있을때 사용한다.

// 1) functionComponenet
//function header () {} //얘는 걍 함수선언문.
// 어떻게 functionComponenet 만들까?
// 1. 반드시 이름은 앞글자가 대문자로 시작해야함.
// 2. 반드시 reactElement를 return해야함.
function Header() {        //대문자로 시작
    return (                 //reactElement 반환
        <header className="header">
            <h1 className="h1">Scoreboard</h1>
            <span className="stats">Players: 1</span>
        </header>
    )
}
//첫번쨰가 대문자면 react Element가 호출된다. 따라서 아래는 Header라는 functionElement실행 후 ReactElement를 반환하게 된다!
ReactDOM.render(<Header></Header>, document.getElementById('root')); //첫번째 파라미터로 JSX올수있음.
//첫번쨰가 소문자면 html로 인식, 대문자면 functionElement로 인식.
// 1) 함수표현식으로 변환하고, 익명함수를 Arrow함수로 변경
// 2) 중괄호 return문 생략 가능
const Header = () =>
    <header className="header">
        <h1 className="h1">Scoreboard</h1>
        <span className="stats">Players: 1</span>
    </header>

const Player = () =>
        <div className="player">
            <span className="player-name">LDK</span>
            <div className="counter">
                <button className="counter-action decrement">-</button>
                <span className="counter-score">35</span>
                <button className="counter-action increment">+</button>
            </div>
        </div>

const App = () =>
      <div className="scoreboard">
          <Header></Header>
          <Player></Player>
      </div>

ReactDOM.render(<App></App>, document.getElementById('root'));

쨘!

React Developer Tool 구글 Extention 설치. Component Tree를 볼 수 있다.

 

과제1) html코드를 컴포넌트화 하기.

 

const TodoApp = () => {
  return (
    <div className="container mt-3">
      <Todoheader />
      <TodoForm />
      <TodoList />
    </div>
  )
}

const Todoheader = () => {
  return (
  <h1 class="text-center">Todo List</h1>
  );
}
const TodoForm = () => {
  return (

  <form class="text-center mb-3">
      <input type="text" class="form-control mb-3"/>
      <button class="btn btn-primary">Add Todo</button>
  </form>
  );
}
const TodoList = () => {
  return (
  <ul class="list-group">
      <Todo/>
  </ul>
  );
}

const todoList = ['영어 공부하기', '자바스크립트 공부하기', '리액트 공부하기'];
const todoArray = [];
for(let i = 0; i < todoList.length; i++){
  let todoString = React.createElement("li", {
    class: "list-group-item d-flex justify-content-between align-items-center"
  }, React.createElement("input", {
    type: "checkbox"
  }), React.createElement("span", {
    class: "flex-grow-1 ml-3"
  }, todoList[i]), React.createElement("button", {
    class: "btn btn-danger"
  }, "Delete"));
  todoArray[i] = todoString;
}

const Todo = () => {
  return [todoArray[0], todoArray[1], todoArray[2]]
}
ReactDOM.render(<TodoApp />,document.getElementById('todo'));
과제 진행중 발생한 issue
1) JSX parsing에러가 났을때 아무런 에러가 뜨지 않아서 디버깅 하기가 어려웠다.
이건 https://codepen.io/ 자체적인건지 아니면 원래 그런건지 모르겠다. 
=> input태그가 닫히지 않아서 발생하는 문제였고 babel try in out(https://babeljs.io/repl)에서 직접 convert(?) test 해보면서 잡았다

2) Todo에 여러개의 태그를 넣고싶었으나 하나의 태그만 가능했다.
Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (8:6)
=> 아직 나머지 공부를 끝내지 않아서 우선은 React Element로 변경 후 자바스크립트로 반복문을 돌렸다..

댓글