들어가며
왜 리액트인가 ?
리액트를 선호하는 이유
- 단방향 바인딩
- 데이터의 흐름이 단방향(부모 → 하위 컴포넌트)
- 장점 : 코드를 이해하기 쉽고, 데이터의 추적과 디버깅이 용이함
- 단점 : 변화를 감지하고 업데이트하는 코드를 매번 작성해야 함
리액트의 역사
2010년대 프론트엔드 개발 환경을 향한 페이스북의 도전
2010년경 JS를 포함한 웹 생태계의 디자인 패턴
- 디자인 패턴 : 어플리케이션 설계 중 자주 발생하는 문제에 대한 모범답안
- MVC 패턴
- Model-View-Controller의 약자
- Model : 정보 및 데이터 관리하는 역할
- View : 브라우저 화면, 사용자 인터페이스 요소 담당
- Controller : 사용자 액션에 의해 이벤트 감지하고 처리하는 역할
- DB에서 필요한 데이터를 불러온 다음, 웹 서버에서 HTML 페이지를 만들어 클라이언트에 제공하면, 프론트는 단순히 서버에서 만든 HTML 페이지를 보여주고 간단한 폼 처리의 역할을 함
- 양방향 데이터 흐름을 가지고 있어, 연쇄적인 데이터 변화가 발생할 수 있음
- 모델과 뷰의 업데이트 예측이 어려워짐
- 이러한 양방향 데이터 흐름을 보완하기 위해 단방향 데이터 흐름 제안
- 데이터가 한 방향으로 흐르기 때문에 각각의 구조가 서로 의지하지 않아 데이터 구조 파악과 흐름을 예측하기 용이함
1장 - 리액트 개발을 위해 꼭 알아야 할 자바스크립트
[1-1] 자바스크립트의 동등 비교
- 리액트에서 JS의 동등 비교 기반
- 리액트의 가상 DOM과 실제 DOM 비교
- 리액트 컴포넌트가 렌더링 여부 판단
- 변수,함수의 메모이제이션 등의 작업
1.1.1 자바스크립트의 데이터 타입
- JS의 모든 값은 데이터 타입을 가짐
데이터 타입
- 원시 타입 (7)
- boolean
- number
- string
- null
- undefined
- symbol
- bigint
- 객체 타입 (1)
- object
원시 타입 (primiitive type)
- 객체가 아닌 다른 모든 타입 의미
- undefined
- 선언한 후 값을 할당하지 않은 변수
- 값이 주어지지 않은 인수에 자동으로 할당되는 값
- 선언만 된 경우
let seo0; console.log(seo0); //undefined
- null
- 의도적으로 값이 없음을 할당한 경우에 사용
- reference 변수에 대한 주소값이 없는 것을 표현
- null은 다른 원시값과 달리 type
✨ null과 undefined의 차이점
내부 메모리적인 측면에서의 차이점
- undefined는 선언만 되고 값이 할당되지 않는 경우
- 변수는 메모리에 존재하지만 값이 없기 때문에 크기가 매우 작음
- 반면, null은 개발자가 의도적으로 값이 없음을 할당하는 경우
- 이때 변수는 빈 객체를 가리키는 객체 포인터이기 때문에 주소값을 나중에라도 받기 위해 크기가 있어 메모리를 차지함
- 즉, undefined 값을 가진 변수의 메모리 용량은 작고 상대적으로 null 값을 가진 변수의 메모리 용량은 크다. (차이가 크진 않음)
- Boolean
- true, false
- true, false처럼 취급되는 truthy,falsy 값 존재
- falsy - fasle, 0, NaN, “”(빈문자열), null, undefined
- truthy - falsy로 취급되는 값 외 모두, 빈 객체와 빈 배열 포함
객체 타입(object type)
- 원시 타입 이외 모든 것 - 배열, 함수 등
- 참조를 전달한다고 해서 참조 타입(reference type)으로도 불림
1.1.2 값을 저장하는 방식의 차이
원시 타입
- 불변 형태의 값으로 저장
- 변수 할당 시점에 메모리 영역을 차지
- 변수의 실제 값을 저장
객체 타입
- 객체는 프로퍼티를 삭제, 추가, 수정할 수 있기 때문에 원시 값과 달리 변경 가능한 형태로 저장
- 객체의 참조값(주소값)을 저장
- 변수에 참조값을 저장하면 객체는 독립적인 메모리 공간(Heap)에 저장되고, 변수에 저장된 메모리 공간의 참조를 저장하게 된다.
- 즉, 변수의 값이 저장된 메모리의 주소인 객체에 대한 참조값이 저장되는 것
1.1.3 자바스크립트의 또 다른 비교 공식, Object.js
- Object.js(x, y) : 두 개의 인수를 받고, 인수의 비교 결과를 반환하는 메서드
- 동등 비교 연산자(==)와의 차이점
- 동등 비교는 양쪽이 같은 타입이 아니면 비교할 수 있도록 강제 형변환한 후 비교
- Object.is는 타입이 다르면 그냥 false
- 일치 비교 연산자(===)와의 차이점
- NaN비교와 +0, -0의 비교가 가능해짐
-0 === +0 // true Object.is(-0, +0) // false Number.NaN === NaN // false Object.is(Number.NaN, NaN) // true NaN === 0 / 0 // false Object.is (NaN, 0 / 0) //true
- 객체 간 비교에 있어서는 ===과 동일
1.1.4 리액트에서의 동등 비교
- 리액트에선 object.is를 이용해 동등 비교를 함 . 구형 브라우저 지원을 위해 폴리필을 함께 사용
- Object.is를 기반으로 동등 비교를 하는 shallowEqual 이라는 함수를 만들어 사용
- 객체의 얕은 비교를 수행하는 함수
- ❓폴리필(Polyfill) : 최신 사양의 기능을 지원하지 않는 브라우저를 위해 누락된 최신 사양의 기능을 구현하여 추가하는 것
- Object.is로 먼저 비교를 수행한 다음, Object.is로 수행하지 못하는 비교,
- 즉, 객체 간 얕은 비교를 shallowEqual으로 한 번 더 수행한다.
- 객체 간 얕은 비교 : 객체의 첫번째 깊이에 존재하는 값만 비교하는 것을 의미
- 객체의 얕은 비교까지만 구현하는 이유는 JSX의 props가 객체이고, 이들 props만 일차적으로 비교하면 되기 때문이다.
[1-2] 함수
1.2.1 함수란 무엇인가 ?
- 작업을 수행하거나 값을 계산하는 등의 과정을 표현하고, 이를 하나의 블록으로 감싸 실행 단위로 만들어 놓은 것
- 리액트에서 컴포넌트를 만드는 함수도 이 함수의 형태를 따름
function Component(props) {
return <div>{props.hello}</div>
}
1.2.2 함수를 정의하는 4가지 방법
1️⃣ 함수 선언문
- JS에서 함수 선언 시 가장 일반적으로 사용하는 방식
- function add(a,b) { return a + b }
- 선언문은 선언만 하고, 어떠한 값도 표현하지 않았음
- 변수에 함수를 할당함으로서 JS 엔진이 표현식으로 해석
- 같은 선언문으로 표현식으로도 사용될 수 있음
const sum = function add(a,b) { return a + b } sum(10, 24); // 34
2️⃣ 함수 표현식
❓일급 객체
- 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체
- 일급 객체 조건
- 변수에 할당할 수 있다
- 다른 함수를 인자로 전달 받는다
- 다른 함수의 결과로서 리턴될 수 있다.
- 함수를 데이터 다루 듯 다룰 수 있다 = 변수에 할당이 가능하다
- const sum = function add(a,b) { return a + b } sum(10, 24); // 34
- 함수 표현식에서 함수명을 생략하는 것이 일반적
- add는 함수 내부에서만 유효
함수 표현식과 선언식의 차이
✅ 호이스팅
- 함수에 대한 선언을 실행 전에 미리 메모리에 등록하는 작업
- 함수를 선언한 코드 이전에 함수를 호출해도 정상 작동
- 코드의 순서에 상관없이 정상적으로 함수를 호출 가능
- 함수 표현식은 런타임 이전에 undefined로 초기화되고, 런타임 시점에 함수가 할당되어 작동함
함수 선언문 사용하는 경우
- 함수를 자유롭게 산언하고 어디서든 자유롭게 호출하고 싶은 경우
- 변수 선언과 다르게 명시적으로 함수를 구별하고 싶은 경우
3️⃣ Function 생성자
const add = new Function('a','b', 'return a + b')
add(10, 24) // 34
- Function 생성자를 사용
- 매개변수 및 함수 로직을 문자열로 작성
- 권장되지 않는 방식
4️⃣ 화살표 함수
- ES6에서 추가된 문법
- function 키워드 대신 ⇒ 화살표 사용
- cosnt add = (a, b) => { return a + b } const add = (a, b) => a + b
✅ 일반 함수와의 차이점
- 생성자 함수로 화살표 사용 불가
- arguments 존재 X
- 화살표 함수에서 this는 상위 스코프의 this를 가리킴
- this : 자신이 속한 객체나 자신이 생성할 인스턴스를 가리키는 값
1.2.3 다양한 함수 살펴보기
즉시 실행 함수 (Immediately Invoked Funcion Expression, IIFE)
- 함수를 정의하는 동시에 즉시 실행되는 함수
- 단 한 번만 호출되며 재호출 불가
- (fuction (a, b) { return a + b }) (10, 24); // 34 ((a, b) => a + b) (10, 24); // 34
- 독립적인 함수 스코프를 운용할 수 있음
- 코드를 읽는 이에게 이 함수가 다시 사용되지 않는다는 것을 각인시킬 수 있어 리팩토링에 도움
- 재사용되지 않고, 단 한 번만 실행되고 쓰이지 않는 경우 사용
2️⃣ 고차 함수
- 함수를 인수로 받거나 결과로 새로운 함수를 받환하는 함수
const doubleArr = [1, 2, 3].map((item) => item * 2)
- 함수 컴포넌트를 인수로 받아 새로운 함수 컴포넌트를 반환하는 고차 함수를 만들 수 있음
1.2.4 함수를 만들 때 주의해야 할 사항
1️⃣ 함수의 부수 효과를 최대한 억제하라
- 함수의 부수 효과(side-effect)란 함수 내의 작동으로 인해 함수가 아닌 함수 외부에 영향을 끼치는 것
- 순수 함수 : 부수 효과가 없는 함수
- 어떤 상황에서도 동일한 인수를 받으면 동일한 결과를 반환
- 비순수 함수 : 부수 효과가 있는 함수
- 컴포넌트 내부에서 API를 호출 → HTTP 요청에 영향
- console.log → 브라우저 콘솔 창에 영향
- 부수 효과를 만드는 것은 피할 수 없는 요소지만 부수 효과를 최대한 억제할 수 있는 방향으로 함수를 설계해야 함
- 리액트에서 부수 효과를 처리하는 훅인 useEffect() 작동 최소화
- useEffect 함수의 역할을 좁히고, 버그를 줄이며, 컴포넌트의 안정성을 높일 수 있음
2️⃣ 가능한 한 함수를 작게 만들어라
- 하나의 함수에서 많은 일을 하지 않게 하는 것
- 하나의 함수가 하나의 일을 하게 되면 함수의 재사용성을 높일 수 있음
3️⃣ 누구나 이해할 수 있는 이름을 붙여라
- 함수 이름은 간결하고 이해하기 쉽게 네이밍
- 직관적인 네이밍을 통해 해당 함수가 어떤 작업을 처리하는지 파악 용이
'React > 모던 리액트 Deep Dive' 카테고리의 다른 글
[3장] 모던 리액트 Deep Dive 스터디 7회차 (0) | 2024.06.17 |
---|---|
[2-3 ~ 2-5] 모던 리액트 Deep Dive 스터디 6회차 (0) | 2024.06.14 |
[2-1 ~ 2-2] 모던 리액트 Deep Dive 스터디 5회차 (1) | 2024.06.12 |
[1-6 ~ 1-7] 모던 리액트 Deep Dive 스터디 4회차 (0) | 2024.06.12 |
[1-3 ~ 1-5] 모던 리액트 Deep Dive 스터디 3회차 (0) | 2024.06.12 |