리액트 1주차 정리

리액트 1주차 정리

리액트를 위한 js 문법 정리

1. var, let, const

요약 : var는 문제가 많다. const와 let를 쓰자. (사용빈도 : const 90% / let 10%)

1-1. var는 문제가 많다

1. 헷갈리는 함수 레벨 스코프
    * 블록 레벨 스코프(Block-level scope)  
        > 모든 코드 블록(함수, if 문, for 문, while 문, try/catch 문 등) 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다. 즉, 코드 블록 내부에서 선언한 변수는 지역 변수이다.  
        __* c, java도 블록 레벨 스코프이다.__
    * 함수 레벨 스코프(Function-level scope)
        > 함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없다. 즉, 함수 내부에서 선언한 변수는 지역 변수이며 함수 외부에서 선언한 변수는 모두 전역 변수이다.  
        __* 심지어 함수 밖의 블록에서 선언해도 전역변수이다!__
    * [참고 링크1-스코프](https://poiemaweb.com/js-scope)
    * [참고 링크2-let, const와 블록 레벨 스코프](https://poiemaweb.com/es6-block-scope)

2. 중복 선언이 가능
3. 생략도 가능  
4. 호이스팅  
    * 함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것
    * 함수 내에서 선언한 함수 범위(function scope)의 변수는 해당 함수의 최상위로,  
    함수 밖에서 선언한 전역 범위(global scope)의 전역 변수는 스크립트 단위의 최상위로 끌어올려진다.
    * 문제는, 선언만 끌어올리지 할당까지 끌어올리진 않는다는 점이다!
    * 이런걸 왜 만든거죠..? -> 아래서 만든 함수를 위에서도 쓸 수 있게
    // var.js

    // 1. 헷갈리는 함수 레벨 스코프

    (function() {
    if (true) {   
        var variable = 'function scope';
    }

    console.log(variable);
    })();


    // 2. 중복 선언이 가능

    (function() {
    var variable = 'function scope';
    var variable = 'duplicated';

    console.log(variable);
    })();


    // 3. 생략도 가능

    (function() {
    variable = 'no var';

    console.log(variable);
    })();

    console.log(variable);


    // 4. 호이스팅

    (function() {
    console.log(variable);

    var variable = 'hoisted';
    })();

    (function() {
    var variable;

    console.log(variable);

    variable = 'hoisted';
    })();

1-2. let은 해결사

  1. 블록 레벨 스코프

  2. 중복 선언 => syntax error

  3. 호이스팅 => syntax error

// let.js

// 1. 블록 레벨 스코프
{
  let variable = 'block scope';

  console.log(variable);
}

// 2. 중복 선언 => SyntaxError
{
  let variable = 'block scope';
  let variable = 'duplicated';

  console.log(variable);
}

// 3. 호이스팅 => ReferenceError
{
  console.log(variable);
  let variable = 'hoisted';
}

1-3. const

let과 같다. 단 하나의 차이는 let은 변경이 가능하고, const는 불가능하단 것

  1. Primitive 타입 : 값 변경 불가능
  2. Reference 타입 : 재할당 불가능, 단 객체의 프로퍼티는 변경될 수 있다.
// const.js


// 1. Primitive
let a = 'a';
a = 'b';
a;

const c = 'c';
c = 'd'; // TypeError
c;


// 2. Reference
let e = {
  foo: 'foo',
};
e = {
  bar: 'bar',
};
e;

const f = {
  foo: 'foo',
};
// f = {
//   foo: 'bar',
// }; TypeError
f.foo = 'bar';
f;

2. template string

싱글쿼터를 사용하며 겪은 불편함이 template string의 등장으로 좀 편해졌다

  • `문자열`
  • `${자바스크립트 표현식} `` // string.js

const name = ‘Daae’;

console.log(‘안녕하세요.\n제 이름은 ‘ + name + ‘ 입니다.’);

console.log(안녕하세요. 제 이름은 ${name} 입니다.);


### 3. arrow function

1. 자신의 this 를 만들지 않는다.
2. 생성자로 사용할 수 없다. 
    * this가 없으니까. 원래 생성자 만들 때 this 해놓고 만들면 거기 값이 박혀 객체가 나왔었음.
3. 항상 익명 함수
    * 그러니 부르고 싶으면 어떠한 변수에 할당하면 된다.
4. 리턴만 있으면, {} 생략 가능
5. 인자가 하나면, () 생략 가능
    * 별 것 아닌 특징들 같지만 파급효과가 컸다.  
    () => a => b => c => d; 이런 것도 가능해진 것임.

// arrow.js

function Foo() { this.name = ‘Mark’;

setTimeout(function() { console.log(this.name); }, 1000);

setTimeout(() => { console.log(this.name); }, 1000); }

const foo = new Foo();

// arrow.js

// 익명 함수를 변수에 대입해서 사용 const a = () => { return ‘리턴’; };

console.log(a());

// 리턴이 바로 표현 가능하면, { return } 생략 const b = () => ‘리턴’; // 여기에 js표현식을 쓸 수 있겠음. 그렇게 쓰려고 많이 만든다.

console.log(b());

// 매개변수가 한개면 () 생략 const c = props => 리턴 ${props};

console.log(c(‘프롭스’));


### 4. 함수.bind(디스)
> 함수의 this 로 인자로 넣은 "디스" 를 사용하는 함수를 만들어 리턴
* 함수를 호출하는 2가지 방법
    * 함수이름();
    * call, apply, bind 메소드 -> this를 자유롭게 할당할 수 있게 해줌
* 어따쓰죠? 함수 재사용 니즈.. 함수를 이렇게 여러 this에 걸쳐 사용할 수 있게 해주는 게 bind다.
* [참고 링크](https://velog.io/@rohkorea86/this-%EC%99%80-callapplybind-%ED%95%A8%EC%88%98-mfjpvb9yap)

// bind.js

function hello() { console.log(안녕하세요 ${this.name}); }

const mark = { name: ‘Mark’, };

const helloMark = hello.bind(mark);

helloMark();

const anna = { name: ‘Anna’, // 2. 이게 this가 되는 것 };

const helloAnna = hello.bind(anna); // 1. 이러면 helloAnna라는 함수가 생기고

helloAnna();


### 5. Destructuring assignment
> 원래 하나만 빼오고 싶을 때 사용하던 방법은 많아지면 힘들어지는데, 이렇게 편하게 필요한 것만 뽑아낼 수 있다.  
뽑아낸 이름과 다르게 쓰고싶으면 그렇게도 가능하다. 

1. 구조분해할당
2. 배열, 객체

// destructuring.js

const foo = { a: ‘에이’, b: ‘비이’, };

// 이렇게 편리하게 뽑아낼 수 있다 const { a, b } = foo; console.log(a, b);

const bar = [‘씨이’, ‘디이’];

const [c, d] = bar; console.log(c, d);

// 새로운 이름으로 할당 const { a: newA, b: newB } = foo; console.log(newA, newB);


### 6. Spread 와 Rest
1. ...
2. 배열, 객체
3. 1 레벨 깊이 복사

* spread

// spread.js

function sum(a, b, c) { return a + b + c; }

console.log(sum(1, 2, 3));

const numbers = [2, 3, 4];

console.log(sum(…numbers)); //원래는 numbers의 0번 1번 이렇게 썼는데, 저렇게 …쓰면 하나하나 분해된 것들을 넣어줌

// spread.js

// 1 레벨 깊이 const obj = { a: 3, b: 4, c: 5 };

const cloned = { …obj, a: 6 }; // 이렇게하면 645 이렇게 만들어짐 (다 들어오고 덮어쓰고싶은거만 덮으면 됨 ) cloned.c = 10; // 이려면 6 4 10

console.log(obj, cloned); // obj는 그대로

// spread.js

// 2 레벨 깊이 const obj1 = { a: { b: 100 } };

const obj1Cloned = { …obj1 }; // 이렇게 레벨이 다른경우 얘를 클론하면 레퍼런스만 복사해줌 obj1Cloned.a.b = 200;

console.log(obj1, obj1Cloned); // 이렇게하면 똑같은게 나올것 우리가 원하는 클론의 결과는 아님

const obj2 = { a: { b: 100 } };

const obj2Cloned = { …obj2, a: { …obj2.a } };// 이러면 원하는대로 딥클론 될 것 그치만 귀찮음 obj2Cloned.a.b = 200;

console.log(obj2, obj2Cloned);


여기서 우리는 일단, 1레벨만 복사된다는 것을 염두하고 가면 된다.  


* rest

// rest.js

function rest1(…args) { console.log(args); // 2. 배열이 나옴 }

rest1(‘mark’, 37, ‘korea’); // 1.이렇게 열거하면

function rest2(name, …args) { console.log(name, args); // 4. 뒤에있는 애들은 배열로 가고 마크는 네임으로 들어가는거. }

rest2(‘mark’, 37, ‘korea’); // 3. 이렇게하면

참고로 4번에서, 거꾸로 ...args, name 하면 에러남 왜? rest 파라미터 뜻 자체가 나머지 파라미터

그러니 뒤에 있어야 하고, 여러 개여도 안 됨

### 7. 비동기처리 이야기
#### 7-1. callback, 과거 비동기 처리를 위한 선택
foo가 끝나고 실행하고 싶다면 이렇게 callback을 이용했으나,  
우리 눈높이에 더 아래에 있으니 헷갈리기도 하고, __callback지옥__ 에 갇히기도 함.

// callback.js

function foo(callback) { setTimeout(() => { // 로직 callback(); }, 1000); }

foo(() => { console.log(‘end’); }); console.log(‘이것이 먼저 실행’);



#### 7-2. promise 객체, 콜백지옥을 끝내러 온 첫번째 출전 선수
1. Promise 객체를 만들고, 로직 처리 후 성공과 실패를 알려준다.
2. then 과 catch 를 통해 메인 로직에 전달한다.

// promise.js

function foo() { return new Promise((resolve, reject) => { setTimeout(() => { // 로직 resolve(); }, 1000); }); }

foo().then(() => { console.log(‘end’); }); console.log(‘이것이 먼저 실행’);


#### 7-2. async - await, 두번째 출전 선수로, 더욱 자연스러운 방법

1. 기본적으로 Promise 를 사용한다. ( 쨘 하고 나온 게 아님 )
2. then 과 catch 를 통해 메인 로직에 전달한다.
3. async 키워드가 붙은 함수 안에서만 await 키워드를 사용할 수 있다.


// async.js

function foo() { return new Promise((resolve, reject) => { setTimeout(() => { // 로직 resolve(); }, 1000); }); }

(async () => { await foo(); //2 console.log(‘end’); //3 console.log(‘이것이 먼저 실행’); // 1 })();


await되면, 해결될 때까지 코드의 흐름을 잠시 기다리는 것 ( 물론 그것만 하는 게 아니다. 다른 건 돌고 있다. ) resolve()되면 다음줄로 넘어감. 


이제 인간의 사고대로?

// async.js

function foo() { return new Promise((resolve, reject) => { setTimeout(() => { // 로직 resolve(); }, 1000); }); }

(async () => { console.log(‘이것이 먼저 실행’); try{ await foo(); console.log(‘end’); }catch{

} })();

아쩌구 main()

이렇게 해놓고보니 메인함수임, js 메인함수. try catch도 많아지고.. 이런 일들이 실무에서 일어나고 있다.

### 8. Generator 객체
> 별로 사용하진 않지만, 리덕스 사가에서 사용하니 보고감. 코어도 Generator기반
1. function* 으로 만들어진 함수를 호출하면 반환되는 객체이다.
2. function* 에서 yield 를 호출하여, 다시 제어권을 넘겨준다.
3. 제너레이터 객체에 next() 함수를 호출하면, 다음 yield 지점까지 간다.
4. 어디다 쓰죠? 비동기하는 애한테 넘겨주면, '야 너 끝나면 나한테 다시 핸들 줘' 할 수 있음
5. 핸들을 넥스트로 넘겨준다, 사가를 쓰면 쉽게 쓴다. 이런 개념이다 정도만.

// generator.js

// 이렇게 * 해주면 리턴값이 generate 객체다. function* foo() { console.log(0.5); yield 1; console.log(1.5); yield 2; console.log(2.5); yield 3; console.log(3.5); }

const g = foo(); // foo()를 호출해 제너레이트 객체를 생성했음 console.log(g.next().value); // next 하면 yield 지점까지 옴 console.log(g.next().value); console.log(g.next().value); console.log(g.next().value); console.log(g.next().value); // 뒤에 없으면 언디파인드가 나온다. 그럼 끝난거

// generator.js

// 핸들 let handle = null;

// 비동기 함수 function bar() { setTimeout(() => { handle.next(‘hello’); }, 1000); }

// 핸들을 통해 컨트롤을 넘기는 제너레이터 함수 function* baz() { const text = yield bar(); console.log(text); }

handle = baz(); handle.next();


여기까지 리액트를 위한 js 문법이었다.  
다음으로 리액트 컨셉을 살펴본다.

## 리액트 컨셉

### Keyword
* View 라이브러리
    * 뷰나 제이쿼리같은 js 라이브러리이다.
* Only Rendering & Update -> 오직 렌더링과 업뎃에만 관여하기 때문에, 페이지 변경은 라우터 돔이 필요하다. 대표적으로 react-라우터-돔이 있다.
    * NOT included another functionality -> 그래서 엑시우스나 페치같은 다른 라이브러리를 사용
* Component Based Development ->이제 프론트에서도 제대로 CDB를 하게 되었다. 원래 윈도우에선 CDB 했었음.
    * 작업의 단위
* Virtual DOM
    * 이제는 DOM 을 직접 다루지 않음. -> 우리는 버출얼 돔과 소통, 버추얼과 리얼 간의 소통은 리액트가!
* JSX -> 일종의 문법이다
    * NOT Templates
    * transpile to JS
* CSR & SSR

### Component Tree => DOM Tree
![component-dom-tree](https://user-images.githubusercontent.com/51072198/71242076-75447d00-2350-11ea-8dc7-b4b96875b712.png)

일반적으로 컴포넌트 계층 구조가 그대로 DOM 계층구조로 이어진다.

### 컴포넌트란?
- src, class, name, props 밖에서 넣어주는 데이터
- 문서(HTML), 스타일(CSS), 동작(JS) 를 합쳐서 __내가 만든 일종의 태그__

<내가지은이름1 name="Mark" />

<내가지은이름 prop={false}>내용</내가지은이름>



### Virtual DOM - diff 로 변경
알아서 다른 점을 찾아 그 부분만 변경해준다

![virtual_dom_diff](https://user-images.githubusercontent.com/51072198/71242272-f69c0f80-2350-11ea-9fac-b6afc13423ca.png)

### React Client Side Rendering vs React Server Side Rendering
> 최근 SSR이 아주 조금 더 빨리 눈에 보이기 때문에 SSR를 써야한다는 의견이 있으나, 0.3초 정도로 별 차이 없음.

* Client Side Rendering : 가져올 땐 껍데기, 리액트가 완료하면 그 때 넣어줌
![CSR](https://user-images.githubusercontent.com/51072198/71242400-38c55100-2351-11ea-85cc-e400fd35e621.png)

* Server Side Rendering : 서버에서 다 만들어서 오는 것
![SSR](https://user-images.githubusercontent.com/51072198/71242399-38c55100-2351-11ea-8172-49b10a755a04.png)

## 리액트 라이브러리
### 리액트가 하는 일
리액트의 핵심 모듈 2가지

import React from ‘react’; import ReactDOM from ‘react-dom’; ```

먼저, react-dom이 하는 일 https://ko.reactjs.org/docs/react-dom.html

  • render()
  • hydrate()
  • unmountComponentAtNode()
  • findDOMNode()
  • createPortal()

이 중 render()를 가장 많이 사용하고, 나머지는 어드밴스 된 것.
우리가 만든 리액트 컴포넌트를 render 해준다.

카테고리:

업데이트: