왜 React에서 자료구조/알고리즘이 중요한가?

leave_a_comment·2026년 5월 21일
post-thumbnail

프론트엔드는 단순히 UI만 그리는 영역이라고 생각하기 쉽지만,
실제로는 렌더링 과정에서 자료구조와 알고리즘 개념이 굉장히 많이 사용된다.

특히 React를 사용하다 보면:

  • useMemo를 쓰는지
  • .map() 남발이 성능에 안 좋은지
  • key가 중요한지
  • Set으로 중복 제거를 하는지

같은 것들이 결국 자료구조/알고리즘 개념과 연결된다.


1. 왜 useMemo가 필요한가

핵심은:

같은 계산을 매 렌더마다 다시 하지 않기 위해

자료구조/알고리즘 관점에서는:

  • 연산 비용 감소
  • 시간복잡도 최소화
  • 캐싱(Cache)

개념에 가깝다.

예를 들어:

const sorted = users.sort(...)

이 코드가 렌더마다 실행되면:

렌더 횟수 × 정렬 비용

이 계속 발생하게 된다.

정렬은 일반적으로:

O(n log n)

복잡도를 가지기 때문에 데이터가 많아질수록 부담이 커진다.


useMemo는 결국 캐싱

useMemo는 내부적으로 보면:

{
  deps: [...],
  cachedValue: result
}

처럼 이전 계산 결과를 저장해두는 개념에 가깝다.

예를 들면:

const sorted = useMemo(() => {
  return users.sort(...)
}, [users])

이렇게 작성하면:

  • users가 변경되지 않는 동안
  • 이전 계산 결과를 재사용

하게 된다.

즉:

불필요한 O(n log n) 연산을 줄이는 것

이 핵심이다.


2. 왜 .map() 남발하면 느릴까

핵심은:

배열 순회는 공짜가 아니다

.map()은 기본적으로:

O(n)

복잡도를 가진다.

예를 들어:

users.map(...)
posts.map(...)
comments.map(...)

이런 코드가 렌더마다 반복되면:

O(n) + O(n) + O(n)

비용이 계속 발생한다.


더 위험한 건 중첩 반복문

예:

users.map(user => {
  posts.map(post => ...)
})

이 경우는:

O(n²)

까지 증가할 수 있다.

React에서 특히 문제가 되는 이유는:

  • state 변경
  • props 변경
  • context 변경

등으로 렌더링이 자주 발생하기 때문이다.

.map()이 렌더마다 계속 반복 실행된다.


실무에서 사용하는 해결 방법

1. Memoization

const items = useMemo(() => {
  return data.map(...)
}, [data])

불필요한 반복 계산을 줄인다.


2. Virtualization

예:

  • FlashList
  • react-window

화면에 보이는 아이템만 렌더링해 렌더 비용을 줄인다.


3. Normalization

배열 대신 객체나 Map 형태로 관리한다.

예:

usersById[user.id]

이런 방식은 탐색 비용을 줄일 수 있다.


3. 왜 key가 중요한가

이건 React의 Diffing 알고리즘과 연결된다.

React는 이전 배열과 새 배열을 비교할 때:

"누가 누구인지"

판별해야 한다.

예:

[
  { id: 1 },
  { id: 2 },
  { id: 3 }
]

React는 key 기반으로 비교한다.

key={item.id}

그런데 index를 쓰면?

예를 들어:

A B C

상태에서 앞에 D가 추가되면:

D A B C

가 된다.

하지만 key={index}를 사용하면 React는:

0 = A → D로 착각
1 = B → A로 착각
2 = C → B로 착각

하게 된다.

그 결과:

  • DOM 재사용 꼬임
  • state 꼬임
  • 불필요한 re-render 증가

같은 문제가 발생할 수 있다.

자료구조 관점으로 보면 결국:

고유 식별자(primary key)

문제에 가깝다.

DB에서 id가 중요한 이유와 비슷하다.


4. 왜 Set으로 중복 제거를 할까

배열에서 중복 검사를 할 때 보통:

arr.includes(x)

를 사용한다.

하지만 includes는:

O(n)

복잡도를 가진다.

예를 들어:

const result = []

for (const item of items) {
  if (!result.includes(item)) {
    result.push(item)
  }
}

이 방식은 최악의 경우:

O(n²)

까지 증가할 수 있다.


Set은 해시 기반

반면 Set은 해시 기반 자료구조라 탐색 비용이 매우 낮다.

const set = new Set(items)

검색은 평균적으로:

O(1)

에 가깝다.

그래서 실무에서는:

const unique = [...new Set(items)]

패턴을 굉장히 자주 사용한다.

예를 들어:

onlineUsers = [...new Set(users)]

처럼 websocket 중복 유저 제거에도 많이 사용된다.


결국 React 성능 최적화도 대부분 자료구조와 알고리즘 개념 위에서 동작한다.

profile
나도 성장하고파

0개의 댓글