| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |
- 리스트랜더링
- 오공완
- map()에는 key값이 필요
- 오공완 #리액트 공부 #React
- React
- 클래스 추가하기 #특정 url 클래스 추가 #사이트 접속시 클래스 추가 #오공완 #javascript
- 리액트
- Today
- Total
목록전체 글 (101)
new_bird-hyun
대규모 트래픽을 받는 서비스나 콘텐츠 변경이 잦은 사이트를 운영하다 보면 정적(Static)의 '빌드 시점'과 서버사이드(SSR)의 '매 요청 시' 렌더링 사이에서 고민하게 됩니다.Next.js의 ISR(Incremental Static Regeneration)은 바로 이 지점에서 빛을 발하는 강력한 기능입니다. ISR은 정적 페이지의 장점(빠른 속도, CDN 캐싱)을 유지하면서도 주기적으로 데이터를 최신 상태로 업데이트할 수 있게 해줍니다.getStaticProps에서 revalidate 옵션을 설정하는 간단한 코드로 시작하지만, 그 내부 동작 원리를 이해하면 더욱 효과적으로 활용할 수 있습니다.export async function getStaticProps() { const res = await..
프로젝트가 커지면서 코드를 복사/붙여넣기 하고 있나요? 혹은 공통 모듈 관리에 어려움을 겪고 있나요? 그럴 때 모노레포를 고려할 수 있습니다.모노레포 도입을 고려할 시점:2개 이상의 프론트엔드 앱 (메인, 어드민 등)을 운영할 때공통 UI 라이브러리나 유틸 함수를 분리하고 싶을 때백엔드와 프론트엔드 코드를 하나의 저장소에서 관리하고 싶을 때Vercel이 인수한 Turborepo를 사용하면, 변경된 코드만 빌드/테스트하여 CI 속도를 획기적으로 개선하고 개발 경험을 통일할 수 있습니다. 무조건적인 도입보다는, 코드 공유의 필요성이 명확해졌을 때가 가장 좋은 타이밍입니다.
3년차 이상의 개발자에게 Storybook은 이미 익숙한 도구입니다. 컴포넌트를 독립적인 환경에서 개발하고, 시각적 회귀 테스트를 자동화하며, 디자이너/기획자와의 소통을 원활하게 만들어주는 필수 툴이죠.하지만 Next.js App Router가 등장하며 한 가지 근본적인 질문이 생겼습니다. "서버에서만 렌더링되는 서버 컴포넌트를 브라우저 환경인 Storybook에서 어떻게 다루어야 할까?"결론부터 말하자면, Storybook은 여전히, 그리고 앞으로도 매우 유용합니다. 단, 역할을 명확히 하고 몇 가지 전략을 사용해야 합니다.1. Storybook의 핵심 역할: UI 컴포넌트 개발에 집중먼저 Storybook은 서버의 데이터를 가져오거나 DB에 직접 접근하는 로직을 테스트하는 도구가 아님을 인정해야 합니..
우리 모두 useToggle, useTabs, useAccordion 같은 커스텀 훅을 만들어 본 경험이 있습니다. 로직을 분리하고 재사용성을 높이는 좋은 방법이죠. 하지만 3년차 개발자라면 여기서 한 걸음 더 나아가야 합니다. "이 훅이 다른 프로젝트, 다른 디자인 시스템에서도 그대로 동작할 수 있는가?"문제점: 로직과 뷰의 암묵적인 결합일반적인 커스텀 훅은 상태와 상태 변경 함수를 반환합니다.// Good: 일반적인 커스텀 훅 const [isOpen, toggle] = useToggle(false);이 훅을 사용하는 컴포넌트는 isOpen 상태에 따라 스스로 aria-expanded 같은 접근성 속성을 관리하고, toggle 함수를 onClick 이벤트에 연결해야 합니다. 이 과정에서 실수가 발생하..
Next.js App Router의 강력함은 캐싱에서 나옵니다. 하지만 많은 개발자들이 데이터 동기화 문제에 부딪혔을 때, 가장 쉬운 해결책인 fetch 옵션에 cache: 'no-store'나 revalidate: 0을 추가하곤 합니다. 이는 Next.js의 가장 큰 장점을 스스로 포기하는 것과 같습니다.패러다임의 전환: 캐시를 '끄는' 것에서 '관리하는' 것으로성숙한 개발자는 캐시를 비활성화하는 대신, 필요할 때 정교하게 무효화하는 방법을 고민해야 합니다. 바로 태그 기반의 On-demand Revalidation이 그 해답입니다.revalidateTag는 어떻게 동작하는가?데이터에 태그 달기: 데이터를 fetch 할 때, next.tags 옵션을 사용해 고유한 태그를 붙여줍니다. 이 태그는 특정 데..
3년차 개발자라면 "모든 것을 서버 컴포넌트로 만들면 좋은가?"라는 질문을 스스로에게 던져본 적이 있을 겁니다. 정답은 '아니오'입니다. 서버 컴포넌트(RSC)와 클라이언트 컴포넌트(CC)는 대립이 아닌, 협력 관계에 있습니다.핵심은 '상호작용'과 '데이터 접근'입니다.상호작용이 없는 순수 UI는 서버 컴포넌트로: useState, useEffect 같은 훅이나 onClick 같은 이벤트 핸들러가 필요 없는 컴포넌트(예: 헤더, 푸터, 정적 정보 표시 영역)는 RSC의 완벽한 후보입니다. 서버에서 렌더링 되어 HTML로 전송되므로 클라이언트 측 JavaScript 번들 크기를 획기적으로 줄여줍니다.상호작용이 필요하면 클라이언트 컴포넌트로: 상태 관리, 이벤트 리스너, 브라우저 API 접근이 필요하다면 주..
npm install @tanstack/react-query// components/UserCardSkeleton.tsx export function UserCardSkeleton() { return ( ); } import { useQuery } from '@tanstack/react-query'; function UserCard() { const { data, isLoading } = useQuery(['user'], () => fetch('/api/user').then((res) => res.json()) ); if (isLoading) return ; return {data.name}님 환영합니다!; }
import { useState, useEffect } from 'react'; import { saveFormState, loadFormState } from './storageUtils'; export default function MultiStepForm() { const [step, setStep] = useState(1); const [form, setForm] = useState({ name: '', age: '' }); useEffect(() => { const saved = loadFormState('form'); if (saved) setForm(saved); }, []); const next = () => { saveFormState('form',..