jQuery는 2006년에 등장한 JavaScript 라이브러리.
당시 웹 개발의 가장 큰 문제는 브라우저마다 JavaScript 동작이 달랐다는 점!
// 익스플로러element.attachEvent('click',function() { ... });// 크롬element.addEventListener('click',function() { ... });// jQuery -> 모든 브라우저에서 동일하게 작동$('element').on('click', function() { ... })
jQuery는 브라우저 호환성 문제를 해결하고, 복잡한 DOM조작을 간단하게 만들어줌!
한 때 전체 웹사이트의 80% 이상이 jQuery를 사용할 정도로 지배적이었음.
jQuery는 DOM을 직접 조작하는 명령형 프로그래밍 방식
// 사용자 정보를 화면에 표시var user = { name: '세비', email: 'Jerry@naver.com', age: 25 };$('#username').text(user.name);
이 방식은:
예를 들어, 쇼핑몰 장바구니 화면에서 아이템 수가 여러 곳에 표시된다면?
→ 모든 곳을 일일히 찾아서 업데이트 해야 함! 하나라도 빼먹는다면 화면과 실제 데이터가 달라짐!
Facebook과 같은 대규모 서비스에서는 아래와 같은 예시의 문제가 발생할 수 있음:
원인:
Model(데이터)와 View(화면)이 서로를 업데이트하는 양방향 흐름 때문!
Model ↔ View ↔ Model ↔ View(서로가 서로를 업데이트할 수 있어 복잡해질 수 있음)// 예시:메시지 읽음 표시(View)→ 읽지 않은 개수 감소(Model)→ 알림 배지 업데이트(View)→ 다른 컴포넌트도 같은 Model 참조→ 동기화 실패 시 불일치 발생// 어디서 상태가 변경됐는지 추적 불가능..
Gmail이나 Google Maps같은 어플리케이션이 등장하면서 앱처럼 매끄러운 웹!에 대한 요구가 커졌음.
사용자가 링크 클릭→ 서버에 새 HTML 요청→ 서버가 새로운 HTML 페이지 전송→ 브라우저가 페이지 전체를 새로 그림// 이 과정에서 깜빡임 발생..!
첫 접속 시 HTML, CSS, JavaScript 한 번만 로드→ 이후 페이지 이동은 JavaScript로 처리→ 필요한 데이터만 서버로 가져옴→ 화면의 일부만 바꿈// 새로고침이 없음
SPA의 장점:
SPA의 과제:
기존의 명령형:
어떻게 화면을 바꿀지 명령
function updateDog(isHappy) {const dog = document.getElementById('dog');if (isHappy) {dog.textContent = '🐶 꼬리 흔듦';} else
새로운 선언형:
무엇을 보여줄지만 선언
function Dog({ isHappy }) {return <div>{isHappy ? '🐶 꼬리 흔듦' : '🐶 축 처짐'}</div>;}
선언적 방식은 “현재 데이터가 이렇다면, 화면은 이렇게 보여야한다” 만 정의!
DOM을 어떻게 조작할지는 프레임워크가 처리하도록!
컴포넌트는 화면을 구성하는 작은 UI 단위로,
버튼, 카드처럼 한 역할만 하도록 만들어서 여러 화면에서 다시 쓰고, 필요할 때 그 부분만 수정할 수 있음.
// 재사용 가능한 버튼 컴포넌트 예시<Button variant="primary" onClick={handleSubmit}>제출</Button><Button variant="danger" onClick={handleDelete}>삭제</Button>
상태 → 화면 → 사용자이벤트 발생!!→ 상태 업데이트 → 화면 자동 업데이트
데이터가 한 방향으로만 흐른다면:
실제 DOM 조작은 느림:
Virtual DOM:
개발자는 전체를 다시 그린다고 생각하며 코드를 작성하지만, 실제로는 변경된 부분만 효율적으로 업데이트됨!
Facebook의 엔지니어 JordanWalke가 2011년 전후 Ads/News Feed 등 점점 복잡해지는 UI를 유지보수 하면서 겪은 문제를 해결하기 위해 시작한 프로젝트가 React!
Facebook Ads 앱이 기능과 팀 규모가 커지면서, 코드 변경이 여러 곳에 연쇄적으로 영향을 미치는 복잡성 때문에 UI 유지보수가 점점 느려지고 예측하기 어려워졌고, 이를 개선하기 위해 새로운 UI 아키텍처가 필요했음!!
“UI를 직접 하나하나 고치는 대신, 현재 상태를 입력으로 해서 UI를 계산하는 함수처럼 생각하자”
function UI(state) {if (state.unreadCount > 0) {return <Badge>{state.unreadCount}</Badge>;} else {
JSX는 JavaScript 안에서 HTML을 작성하는 문법
function Welcome({ name }) {return <h1>Hello, {name}!</h1>;}function TodoList({ todos }) {
매번 전체 화면을 다시 계산하면 느려질 수 있으니, React는 실제 DOM 대신 Virtual DOM이라는 가벼운 트리 구조를 메모리 안에 만들었음!
setTodo([...todos, { id: 3, text: '드라마보기'}]);// 상태 변경이 일어나면?// → 새 Virtual DOM 생성// → 이전 Virtual DOM 과 비교// (ex. "li 두 개는 그대로, li 하나가 추가되었구나!")// → 달라진 부분만 실제 DOM에 반영
function SearchBox() {const [keyword, setKeyword] = useState('');return (<div><inputvalue={keyword}
데이터 흐름을 보면:
React는 기본적으로 단방향 데이터 플로우를 사용함.
상위 컴포넌트 → 하위 컴포넌트 방향으로 데이터가 흘러가고, 상태변경은 setState / useState 같은 명시적인 함수로만 가능!
React 팀이 Hooks를 도입할 때 공식적으로 말한 문제는 크게 세 가지:
class Counter extends React.Component {constructor(props) {
class Counter extends React.Component {state = { count: 0 };componentDidMount() {
Hooks로 개선:
React팀은 공식 블로그에서 “로직 재사용과 코드 구조를 개선하기 위해” Hooks를 도입했다고 밝힘.
function Counter() {const [count, setCount] = useState(0);function handleClick()
CSR의 SEO문제:
Vue는 Google에서 일하던 Evan You가 2013년-2014년 초 사이에 개발한 프레임워크.
Evan You는 Google에서 여러 UI 프로토타입을 빠르게 만드는 업무를 하며 AngularJS를 사용했음. Angular가 가진 데이터 바인딩과 DOM 업데이트 방식 자체는 마음에 들었지만, 프로토타입을 빠르게 만들기에는 너무 무겁고 복잡하다고 느꼈음.
“내가 Angular에서 정말 좋았던 부분만 뽑아낸 다음, 추가적인 모든 개념을 동반하지 않고 무언가를 정말 가볍게 만들어보면 어떨까? 하고 생각했습니다.” - Evan You 인터뷰
이에 Evan You는 이런 생각을 가짐:
이러한 생각을 바탕으로 Angular에서 본인이 유용하다고 느낀 부분만을 추려 보다 단순한 UI 프레임워크를 실험적으로 개발했고, 그 결과물이 2014년 2월 공개된 Vue..!
Vue는 대기업의 지원 없이 순수하게 커뮤니티 주도로 성장한 독특한 사례로, Evan You는 2016년부터 Patreon을 통한 크라우드펀딩으로 Vue를 풀타임으로 개발하기 시작했음.
+Vite 만든 사람..! = Vue 만든 사람 = Evan You
“점진적 프레임워크(Progressive Framework)”
Vue의 공식 문서에서는 “당신과 함께 성장하고 당신의 필요에 맞춰 적응할 수 있는 프레임워크”라고 기술되어이 있기도 함.
점진적이라는 것의 의미:
이런 접근 방식은 처음부터 모든 기능을 포함한 단일 구조의 프레임워크를 제공하는 Angular와 의도적으로 다른 선택..!
<template><h1>{{ message }}</h1></template>
폼 입력과 데이터 상태를 자동으로 동기화하는 양방향 데이터 바인딩을 공식적으로 지원함.
<input v-model="message" />
Vue는 파일 하나에 템플릿, 로직, 스타일을 명확히 구분된 블록으로 관리하는 방식을 제공함.
<template>...</template><script>...</script><style scoped>...</style>// 이렇게 하나의 파일에 관리
CompositionAPI는 로직 재사용과 코드 구조 개선을 목표로 추가된 기능임.
React Hooks와 유사한 점:
기존 Options API:
<script>export default {data() {return {count: 0}},methods: {increment()
새로운 Composition API:
<script setup>import { ref, onMounted } from 'vue'const count = ref(0)function increment() {count.value++}
2016년 Vercel의 CEO Guillermo Rauch가 개발한 React 기반 풀스택 프레임워크임.
Guillermo Rauch는 Socket.IO 등 영향력 있는 오픈소스 프로젝트를 만든 개발자로, 웹 어플리케이션을 실제 서비스로 배포하는 과정이 지나치게 복잡하다는 생각을 가지고 있었음.
생각한 문제들:
React는 UI라이브러리로서의 역할은 잘 해냈지만, 실제 서비스를 만들기 위해 필요한 전반적인 개발 환경과 구조는 개발자가 직접 구성해야 했음.
당시 React만으로 SPA를 구성할 경우:
Google이나 Meta에서도 서버 렌더링이나 성능 최적화와 같은 기술을 오픈소스로 공개하긴 했지만,
이를 실제 서비스에 적용하려면 개발자가 설정을 직접 구성하고 구조를 이해해야 했음.
Guillermo는 인터뷰에서 "Google Docs가 워드 프로세싱을, Figma가 디자인을 단순화한 것처럼, Next.js는 웹 개발을 단순화하려 했다"고 설명함.
그래서 Next.js는:
Next.js의 가장 큰 특징은 페이지별로 다른 렌더링 방식을 선택할 수 있다는 것!
정적 생성 (Static Site Generation, SSG):
→ 미리 만들어 두고 바로 보여주는 방식
// 빌드 시 HTML을 미리 생성export async function getStaticProps({ params }) {const post = await getPostById(params.id)return { props: { post } }
서버에서 렌더링 (Server-Side Rendering, SSR):
→ 요청이 올 때마다 서버에서 새로 만들어주는 방식
// 요청할 때마다 서버에서 HTML 생성export async function getServerSideProps(context) {const data = await fetchUserData()return { props: { data } }}
필요할 때만 다시 생성 (Incremental Static Regeneration, ISR):
→ 기본은 정적 페이지, 필요할 때만 다시 만드는 방식
export async function getStaticProps() {return {props: { products },revalidate: 60 // 60초마다 백그라운드에서 새로 생성}}
브라우저에서 렌더링 (Client-Side Rendering, CSR):
→ 브라우저에서 JavaScript로 화면을 만드는 방식
pages/index.js → /about.js → /aboutblog/index.js → /blogblog/[slug].js → /blog/글-id
// /api/users 로 접근 가능export default function handler(req, res) {if (req.method === 'POST') {res.status(200).json({ name
const HeavyComponent = dynamic(() => import('../components/HeavyComponent'))
이렇게 되면:
<Imagesrc="/profile.jpg"alt="프로필"width={500}height={500}/>
자동으로 처리되는 것들:
→ 개발자는 이미지 성능을 따로 신경쓰지 않아도 됨.
→ React의 기본 CSR 방식에서 어려웠던 SEO 문제를 해결함.
→ Vercel을 쓰는 게 가장 수월한 구조
서버 사이드 렌더링을 많이 사용하는 경우:
→ 트래픽이 많은 서비스에서는 비용을 함께 고려해야 함.
| 구분 | React | Vue | Next.js |
| 성격 | UI 라이브러리 | 프레임워크 | React 기반 풀스택 프레임워크 |
| 최초 공개 | 2013년 | 2014년 | 2016년 |
| 주요 주체 | Meta (Facebook) | Evan You + 커뮤니티 | Vercel |
| 데이터 흐름 | 단방향 | 양방향 (v-model) | 단방향 (React 기반) |
| 템플릿 | JSX |
*출처: GitHub, npm 관련 정보는 2025년 기준 GitHub, npm trends의 자료
번들 크기란:
웹사이트를 열 때, 브라우저가 다운로드해야 하는 JavaScript 파일의 크기. 작을수록 페이지가 빨리 뜸!
때문에 번들 크기는 초기 로딩 속도에 직접적인 영향을 미치기에 중요 요소!
실제 앱 크기는 어떤 라이브러리를 쓰냐에 따라 많이 달라져서 참고 정도만!
상태 변경→ 새 Virtual DOM 생성→ 이전 Virtual DOM과 비교→ 차이점만 실제 DOM에 반영
데이터 변경→ Proxy가 자동 감지→ 해당 데이터를 쓰는 컴포넌트만 리렌더링→ Virtual DOM 비교 → DOM 반영
React의 렌더링 방식을 그대로 쓰면서, 언제 렌더링할지를 선택할 수 있게 함.
# CSR브라우저에서 JS로 렌더링# SSR요청마다 서버에서 HTML 생성# SSG빌드할 때 미리 HTML 생성# ISRSSG + 주기적으로 재생성
const [value, setValue] = useState('');<input value={value} onChange={(e) => setValue(e.target.value)} />
<input v-model="value" />
→ 복잡한 상태 관리가 필요한 서비스: 대시보드, 실시간 협업 툴, 채팅 앱 등
→ 폼이 많은 서비스: 양방향 바인딩(v-model)으로 입력 폼 처리가 편함
→ SEO가 중요한 사이트: 블로그, 마케팅 페이지, 이커머스 등 → 콘텐츠 중심 서비스: 정적 페이지가 많고, 업데이트 주기가 일정한 경우
React · Vue · Next.js 모두 활발히 발전 중 -! 프로젝트 요구사항과 팀 상황에 맞게 선택해서 사용하도록 하는 게 제일 중요!
function Counter() {const [count, setCount] = useState(0);useEffect(() => {document.title = `count: ${count}`;}, [count]);return (<button onClick={() => setCount(count + 1)}>{count}</button>);}
| HTML 기반 템플릿 |
| JSX |
| SSR 지원 | 별도 설정 필요 | Nuxt 사용 | 기본 내장 |
| GitHub Stars (대략적인 수준) | 약 242K | 약 52K | 약 137K |
| npm 주간 다운로드 (대략적인 수준) | 약 32M | 약 6.4M | 약 8M |