🌸
react-frontend ) til - 20240527
May 27, 2024
모던 리액트 Deep Dive
들어가면서
- 해당 내용은 인강을 통해 들었던 내용이 있으나, 개념적으로 부족한 부분이 있는 것으로 판단되어, 조금 더 기본이 되는 근본적인 내용을 정리하기 위하여
모던 리액트 Deep Dive
초반 부분의 독서 및 정리한 내용이다. - 필요하거나, 중요하다고 생각하는 내용만을 담고 있다. 주의!
- 챕터 상의 3차 목차에 대해서 제목으로 지정하며, 보고 알아둬야 하는 부분은 페이지까지 기록한다.
01 장 리액트 개발을 위해 꼭 알아야 할 자바스크립트
1.1 자바스크립트의 동등 비교
리액트와 함께 사용 가능한 다른 라이브러리들 21p~
- 상태관리 : Redux, Zustand, Recoil, Jotai
- 서버 사이드 렌더링 : Next.js, Remix, Hydrogen
- 애니메이션 : Framer Motion, react-spring, React Move
- 차트 : Rechats, visx, nivo
- 폼 : React Hook Form, Fromik, React Final Form
JS에서 undefined, null 의 의미 21p~
- undefined : 선언은 됐지만, 할당되지 않은 값
- null : 명시적으로 값이 들어 있지 않음을 나타내는 값
truthy / falsy 22p~
- 조건문 상에서 true나 false 값은 아니지만, 같은 취급을 받는 값
- truthy
{}
[]
1
- falsy
- 0, -0, 0n, 0x0n
- NaN
- 빈 문자열(싱글, 쌍 따옴표, 백틱) : 문자열에 값이 없으면 falsy 취급을 받는다.
- null
- undefined
Symbol 26p~
- ES6에서 추가된 7번째 타입. 고유한 값을 위해 만들어진 타입. 심볼타입은 같은 값을 인수로 넘겨줘도 온전히 고유한 값으로만 취급 받는다.
const key = Symbol('key')
const key2 = Symbol('key')
key === key2 // false
// 동일한 값을 사용하기 위해서는
// 다음 static 메소드를 활용해야 한다.
Symbol.for('hello') === Symbol.for('hello')
// true
객체 타입 26p~
typeof
데이터 타입을 알려주는 역할을 한다.
typeof [] === 'object' // true
typeof {} === 'object' // true
function hello() {}
typeof hello === 'function' // true
자바스크립트의 또 다른 비교 공식, Object.is 29p~
- 두개의 인수를 받고, 인수가 두개가 동일한지를 확인하는 반환 메서드
- 하지만
==
,===
와는 다른 점이 있다.==
는 같음 비교 전에 양쪽 타입이 다르면 강제 형변환이 일어난다. 즉, 5==
‘5’ 는 같음 취급을 한다. 하지만 Object.is 는 false 취급으로===
와 같게 결과가 나온다.===
의 경우와 다르게 좀더 개발자가 기대하는 방식으로 정확한 비교가 이루어진다.-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
- 단, 객체의 비교에서는 별 차이가 없다.
Object.is({}, {}) // false const a = { hello: 'hi', } const b = a Object.is(a, b) // true a === b // true
- ES6 에서 추가 되었으며,
===
가 가지는 한계를 극복하기 위해 만들어졌으나, 자바스크립트의 특징으로 객체에서는 동일하게 작동한다.
리액트에서의 동등 비교 30p~
- 리액트에서는 기본적으로 Object.is 를 기반으로
shallowEqual
라는 함수를 만들어 동등 비교를 진행한다. - Object.is 로 먼저 비교하고, 수행한 다음, Object.is에서 수행하지 못하는 비교, 즉, 객체 간의 얕은 비교를 한번더 수행하고, 첫 번째 깊이의 값을 확인하는 식으로 진행한다. 이렇게 되는 가장 중요한 포인트는 props 만 일차적으로 비교하면 되기 때문이다.
- 그렇기 때문에 props가 깊어지는 경우, 즉 한 객체 안에 추가 객체가 있으면, 컴포넌트에서 실제로 변경된 값이 없음에도 불구하고 메모이제이션된 컴포넌트를 반환하지 못함.
- 단, 이러한 점은 단점이라기 보단 내부 객체까지 완벽하게 재귀로 비교하는 식으로 구현하게 되었을 경우 있을 성능적 악영향 때문이다.
1.1.5 정리 34p
- 자바스크립트에서 객체 비교의 불안전성은 반드시 개발자가 알아둬야 하는 지점이다.
- 리액트는 이러한 언어적 한계를 뛰어넘을 수 없어 얕은 비교만을 사용해 비교를 수행해 필요한 기능을 구현하고 있다.
- 따라서 이러한 특징의 숙지는 향후 함수형 컴포넌트에서 사용되는 훅의 의존성 배열의 비교, 렌더링 방지를 넘어선 useMemo, useCallback의 필요성, 렌더링 최적화를 위해 꼭 필요한 React.memo를 올바르게 작동시키기 위해 고려해야 할 것들을 쉽게 이해할 수 있을 것이다.
1.2 함수
1.2.1. 함수란 무엇인가 34p
// JS의 기본적인 함수 형태
function sum(a, b) {
return a + b
}
// React 컴포넌트의 기본 형태
function Component(props) {
return <div>{props.hello}</div>
}
1.2.2 함수를 정의하는 4가지 방법
- 함수 선언문
// 일반문 방식 function add(a, b) { return a + b } // 선언문 방식 const sum = function sum(a, b) { return a + b }
- 함수 표현식
- 일급 객체 : 다른 객체들에게 일반적으로 적용 가능한 연산을 모두 지원하는 객체. ≓ 자바스크립트 함수
// 함수 표현식에서 할당하려는 함수의 이름은 // 생략하는 것이 일반적 // 이렇게 하는 이유는 혼란 방지용이다. // console.log(typeof sum) // 에러가 발생한다. // ReferenceError: Cannot access 'sum' before initialization // sum() const sum = function (a, b) { return a + b } console.log(sum(4, 5)) // 9 console.log(typeof hello === 'undefined') // true // hello() // Uncaught TypeError: hello is not a function var hello = function () { console.log('hello') } hello()
- 두 방식의 차이는 호이스팅과 관련있다.
- 함수의 호이스팅은 한마디로 미리 메모리에 등록하는 작업으로, 코드의 순서와 상관없이 동작하는 형태를 말한다.
- 이때 함수 선언문의 방식은 미리 저장된다.
- 하지만, 함수 표현식 var의 경우 undefined 로 초기화되어 함수로 사용 자체는 안된다.
- 추가로 const의 경우 아예 호이스팅에 포함되지않는다.(이는 선언시의 var, const의 차이에서 온다. )
- 둘은 서로 장단점이 있으니 현재의 개발 환경, 본인이나 프로젝트 상황에 맞춰서 작성법을 일관하게 사용하면 충분하다.
- Function 생성자
const add = new Function ('a', 'b', 'return a + b') add(10, 24) // 34
- 그냥 쓰지 말자.
- 화살표 함수
- 글자수를 줄일 수 있다는 점 등의 측면으로 많이 사용된다.
const add = (a, b) => { return a + b } const add = (a, b) => a + b
- 단, 특징적인 차이점이 상당히 있다.
- 생성자 함수로 사용이 불가능하다.
arguments
존재하지 않음- 이는 함수 내에서 사용 가능한 유사 배열 객체로, 따로 함수로 전달된 인수를 적지 않아도, 해당 키워드로 가변 배열로 값들을 받아와서 사용이 가능하다.
- 이 외에도 기존 함수 오버로드, 특정 인자수 미리 알수 없는 함수 구현 등에서 쓰일 수 있다.
- this 바인딩에서 차이가 발생함. 기본적으로 this 는 함수가 어떻게 호출 되느냐에 따른 동적 바인딩의 구조였지만, 화살표 함수는 함수 자체의 바인딩을 갖지 않고, 상위 스코프의 this를 따른다(!)
// class 형 컴포넌트에서 일반 함수와 화살표 함수로 state 를 갱신하는 예지
class Component exteds React.Component {
constructor(props) {
super(props)
this.state = {
counter: 1,
}
}
functionCountUp() {
console.log(this) // undefined
this.setState((prev) => ({ counter: prev.counter + 1}))
}
ArrowFunctionCountUp = () => {
console.log(this) // class component
this.setState((prev) => ({ counter: prev.counter + 1}))
}
render() {
return (
<div>
{/* Cannot read properties of undefined (reading 'setState')*/}
<button onClick={this.functionCountUp}>일반함수</button>
{/* 정상적으로 작동한다. */}
<button onClick={this.ArrowFunctionCountUp}>화살표 함수</button>
</div>
)
}
}