[모던 리액트 Deep Dive] 1장 리액트 개발을 위해 꼭 알아야 할 자바스크립트2

하니·2025년 5월 30일

React 길잡이

목록 보기
19/21

💠 리액트에서 자주 사용하는 JS 문법

ECMAScript : 자바스크립트 표준
바벨 : JS의 최신 문법을 다양한 브라우저에서도 일괄적으로 지원할 수 있도록 코드를 트랜스파일한다. ES5

구조 분해 할당

배열 또는 객체의 값을 분해해 개별 변수에 즉시 할당한다.

  • 객체배열 구조 분해 할당은 사용하는 쪽에서 원하는 이름을 변경하는 것이 번거롭다자유롭다.

배열 구조 분해 할당

✔️ ,의 위치에 따라 값이 결정된다.

const arr = [1, 2, 3, 4, 5]
const [first, , , , fifth] = arr // 2, 3, 4는 변수 할당 생략

first // 1
fifth // 5

✔️ 기본값 선언

  • undefined일 때만 기본값을 사용한다.

    const arr = [1, 2]
    const [a=10, b=10, c=10] = arr
    // a 1
    // b 2
    // c 10
    const [a=1, b=1, c=1, d=1, e=1] = [undefined, null, 0, '']
    a // 1 (기본값)
    b // null
    c // 0
    d // ''
    e // 1 (기본값)
  • 특정값 이후의 값을 다시 배열로 선언하고 싶은 경우, 스프레드 연산자를 사용한다.
    이때 맨 마지막 위치에만 스프레드를 사용할 수 있다.

    const arr = [1, 2, 3, 4, 5]
    const [first, ...rest] = arr
    // first 1
    // rest [2, 3, 4, 5]

객체 구조 분해 할당

객체는 객네 내부 이름으로 꺼내온다.

const object = {
	a: 1,
  	b: 2,
  	c: 3,
  	d: 4,
  	e: 5,
}

const {a, b, c, ...objectRest} = object
// a 1
// b 2
// c 3
// objectRest = {d:4 , e: 5}

✔️ 새로운 이름으로 재할당 가능

const object = {
  a: 1,
  b: 2,
}
const {a: first, b: second} = object
// first 1
// second 2

✔️ 기본값 선언, 스프레드 연산자 모두 가능 (위 배열 구조 분해 할당 참고)

✔️ 리액트 컴포넌트인 props에서 값을 바로 꺼내올 때 자주 사용

function SampleComponent({a, b}) { // "props"에서 a, b를 바로 꺼냄
  return a + b // "props.a + props.b"가 아니라 바로 a, b 사용 가능
}

SampleComponent({a: 3, b: 5}); // 기본값

✔️ 값으로 꺼내오는 것뿐만 아니라, 변수의 값으로 꺼내오는 계산된 속성 이름 방식
(일반적)

const object = { a: 1, b: 2 }
const { a } = object  // 'a'라는 고정된 이름으로 꺼냄

계산된 속성 이름 방식

  • 변수 네이밍:a 안하면 에러 발생
const key = 'a'
const object = {
	a: 1,
  	b: 1,
}

const { [key]: a } = object // key의 값인 "a"라는 속성 이름을 가진 값을 찾고 
// : a -> 변수명을 선언해준다.
// a = 1

전개 구문

✔️ 배열의 전개 구문

  • 과거에는 배열 간 합성 시, push() concat() splice() 메서드 사용
// 스프레드 안쓰고
const arr1 = ['a', 'b']
const arr2 = arr1

arr1 === arr2 // true : 내용이 아닌 참조 복사

// 1차원
const arr1 = ['a', 'b']
const arr2 = [...arr1]

arr1 === arr2 // false : 실제로 값만 복사되고, 참조는 다름

// 2차원
const arr1 = [['a', 'b'], ['c', 'd']]
const arr2 = [...arr1]

arr1 === arr2        // false (여전히 다른 배열)
arr1[0] === arr2[0]  // true (내부 배열은 같은 참조)

✔️ 객체의 전개 구문

  • 같은 키가 있다면, 순서에 따라 마지막이 덮어쓰니 주의하자
const obj1 = {
	a: 1,
  	b: 2,
}
const obj2 = {
	c: 3,
  	d: 4,
}

const newObj = {...obj1, ...obj2}
// {"a: 1, "b": 2, "c": 3, "d": 4}

객체 초기자

객체 선언 시, 객체에 넣으려는 키와 값을 지닌 변수가 이미 존재한다면, 해당 값을 간결하게 넣어주는 방식

const a = 1
const b = 2

const obj = {
	a, // 원래는 a: a,
  	b, // b: b,
}
// {a: 1, b: 2}

Array 프로토타입 메서드: map, filter, reduce, forEach

기존 배열의 값을 건드리지 않고 새로운 값을 만들어낸다.

리액트에서..
Array.prototype.map : 똑같은 길이의 새로운 배열을 반환하는 메서드

  • 특정 배열 기반으로 리액트 요소 반환할 경우

Array.prototype.filter : truthy 조건을 만족하는 경우에만 해당 원소를 반환하는 메소드

  • 기존 배열에 대해 어떠한 조건을 만족하는 새로우 배열 반환할 경우

Array.prototype.reduce : 초깃값에 따라 배열이나 객체 또는 다른 무언가를 반환할 수 있는 메서드 (누적 결과)

  • 배열을 원하는 하나의 객체로 변환하는 경우

Array.prototype.forEach : 단순히 콜백 함수 실행기만 하는 메서드
반환값 X
break, return을 이용해도 배열 순회를 멈출 수 X O(n)

💠 타입스크립트

리액트 코드를 효과적으로 작성하기 위한 활용법

any 대신 unknown을 사용하자

불가피하게 이작 타입을 단정할 수 없는 경우

// typeof를 사용해서 unknown에 직접 접근하는 대신,
// 해당 unknown 값이 우리가 원하는 타입일 때만 의도대로 작동하도록

function doSomething(callback: unknown) {
	if (typeof callback === 'function') {
    	callback()
      	return
    }
  	throw new Error('callback은 함수여야 합니다.')
}

✔️ unknown ↔️ never
코드상으로 존재가 불가능한 타입을 나타낼 경우

ex) TS로 클래스 컴포넌트를 선언할 때, props는 없지만 state가 존재하는 상황에서, 어떠한 props도 받아들이지 않는다는 의미로 사용

타입 가드를 적극 활용하자

✔️ instanceof
: 지정한 인스턴스가 특정 클래스의 인스턴스인지 확인할 수 있는 연산자

ex) unknwon으로 내려오는 에러 > 타입 가드를 통해 각 에러에 따라 원하는 처리 내용 추가

class UnAuthrizedError extends Error {
	// ...
}

...

async function fetchSomething() {
	try {
    	const response = await fetch('/api/something')
        return await response.json()
    } catch (e) {
    	// e는 unknown이다.
      	
      	// UnAuthorizedError를 위한 타입 가드 조건문
      	if (e instanceof UnAuthorizedError) {
        	// ...
        }
      	// UnExpenctedError를 위한 타입 가드 조건문
      	if (e instanceof UnExpectedError) {
        	// ...
        }
      
      	throw e
    }
}

✔️ typeof
특정 요소에 대해 자료형을 확인하는 데 사용된다.

function logging(value: string | undefined) {
	if (typeof value === 'string') {
    	console.log(value)
    }
  	if (typeof value === 'undefined') {
    	return
    }
}

✔️ in
property in object > 어떤 객체에 키가 존재하는지 확인 용도

interface Student {
	age: number
    score: number
}
interface Teacher {
	name: string
}

function doSchool(person: Student | Teacher) {
	if ('age' in person) {
    	person.age
      	person.score
    }
  	if ('name' in person) {
    	person.name
    }
}

제네릭

단일 타입이 아닌 다양한 타입에 대응할 수 있도록 도와주는 도구

✔️ useState는 기본값을 넘기지 않고 사용하는 경우가 많은데, 값을 undefined로 추론하는 문제 발생 > 제네릭으로 기본값 선언

const [state, setState] = useState<string>('')

✔️ 제네릭을 하나 이상 사용할 경우, 알파벳 T, U 대신 적절히 네이밍하는 것이 좋다.

function multipleGeneric<First, Last>(a1: First, a2: Last): [First, Last] {
	return [a1, a2]
}
const [a, b] = multipleGeneric<string, boolean>('true', true)

a // string
b // boolean

인덱스 시그니처

객체의 키를 정의하는 방식

동적인 객체를 정의할 때 유용하다. > 객체의 키는 동적으로 선언되는 경우 최대한 지양하자!

type Hello = {
	[key: string]: string // 키의 범위가 너무 커지기 때문에 존재하지 X는 키로 접근 시, undefined 반환
}

✔️ 객체의 키를 좁히는 방법
1. record 사용

type Hello = Record<'hello' | 'Hi', string>
  1. 타입을 사용한 인덱스 시그니처
type Hello = { [key in 'hello' | 'hi']: string }

❗️ 객체에 인덱스 시그니처 사용할 경우 발생할 수 있는 이슈

type Hello = {
	[key: string]: string 
}

const hello: Hello = {
	hello: 'hello',
  	hi: 'hi'
}

Object.keys(hello).map((key) => {
 // Error: Element implicitly has an 'any' type because expression of type 'string'
 // can't be used to index type 'Hello'.
 // No index signature with a parameter of type 'string' was found on type 'Hello'.
 const value = hello[key]
 return value
})

Object.keys(hello)의 반환 타입 : string[] ➡️ string은 인덱스 키로 접근할 수 없다!

  • ['hello', 'hi']를 반환하지만, TypeScript는 이걸 그냥 string[] 이라고 본다.
  • TypeScript는 '혹시 없는 키로 접근하면 어떡하지?' 라고 걱정해서, string 타입으로는 객체 접근을 막는다. (확실한 키로만 접근하게 함)

🔒
내가 key를 string type으로 선언해뒀음에도 불구하고
실제 사용할할 때는 TypeScript가 없는 키로 접근하는 경우를 막기 위해
확실한 키가 아니면 에러를 발생시킨다.

🙆🏻‍♀️ Object.keys에 대한 반환 타입을 string[] 대신 개발자가 단언한 타입으로 강제하는 방법

// Object.keys(hello)를 as로 타입을 단언하는 방법
(Object.keys(hello) as Array<keyof Hello>).map((key) => {
	const value = hello[key]
    return value
})

🙆🏻‍♀️ keysOf라고 하는 Object.key를 대신할 함수를 만드는 방법
객체의 키를 가지고 오면서 동시에 가져온 배열에 대해서도 타입 단언으로 처리한다.

// 타입 가드 함수를 만드는 방법
function keysOf<T extends Object>(obj: T): Array<keyof T> {
	return Array.from(Object.keys(obj)) as Array<keyof T>
}
    
keysOf(hello).map((key) => {
	const value = hello[key]
    return value
})

🙆🏻‍♀️ 가져온 키를 단언하는 방법

// 가져온 key를 단언하는 방법
Object.keys(hello).map((key) => {
	const value = hello[key as keyof Hello]
    return value
})
profile
Hi, I am HANI Developer(╹◡╹). .....1hani me?

0개의 댓글