리액트 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은 해결사
-
블록 레벨 스코프
-
중복 선언 => syntax error
-
호이스팅 => 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는 불가능하단 것
- Primitive 타입 : 값 변경 불가능
- 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) 를 합쳐서 __내가 만든 일종의 태그__
<내가지은이름 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 해준다.