본문 바로가기

전체 글

(384)
[React 2026-10-07] React 접근성(a11y)과 포커스 관리 - 시맨틱 요소, label과 aria 연결, 모달 포커스 이동/복원, 포커스 트랩, 방향키 내비게이션, aria-live 알림 접근성(Accessibility, 줄여서 a11y)은 시각 장애인이 사용하는 스크린 리더, 마우스 대신 키보드만 사용하는 사용자, 일시적으로 한 손만 쓸 수 있는 사용자 등 모든 사람이 서비스를 사용할 수 있도록 만드는 것입니다. 공공기관과 많은 기업에서 웹 접근성 인증을 요구하고 있고, 접근성이 좋은 마크업은 검색 엔진 최적화와 자동화 테스트에도 도움이 됩니다. React로 만든 화면은 상태에 따라 DOM이 계속 바뀌기 때문에, 정적인 HTML보다 신경 써야 할 부분이 더 있습니다. 특히 포커스 관리(모달을 열고 닫을 때 키보드 포커스가 어디로 가는가)와 동적으로 바뀌는 내용 알리기는 React 개발자가 직접 챙겨야 합니다. 이번 글에서는 React에서 자주 놓치는 접근성 포인트를 예제로 확인하고, 모..
[React 2026-10-07] IntersectionObserver와 ResizeObserver 커스텀 훅 만들기 - useInView, 이미지 지연 로딩, 무한 스크롤, useElementSize, 컨테이너 기준 반응형, React 19 ref 콜백 cleanup "요소가 화면에 보이기 시작하면 무언가를 하고 싶다", "요소의 크기가 바뀌면 레이아웃을 바꾸고 싶다"는 요구는 프론트엔드에서 아주 흔합니다. 예전에는 scroll, resize 이벤트에서 getBoundingClientRect()를 계속 호출하는 방식으로 구현했지만, 이 방식은 이벤트가 매우 자주 발생해 성능에 부담이 큽니다. 브라우저는 이를 위해 두 가지 Observer API를 제공합니다. - IntersectionObserver : 요소가 뷰포트(또는 지정한 스크롤 영역)와 겹치는지, 얼마나 겹치는지 비동기로 알려 줍니다.- ResizeObserver : 요소의 크기가 바뀔 때마다 새 크기를 알려 줍니다. 창 크기뿐 아니라 부모 레이아웃 변화, 내용 변화로 인한 크기 변화도 감지합니다. 이 API..
[React 2026-10-07] dangerouslySetInnerHTML과 XSS 방지 - JSX 자동 이스케이프, HTML 문자열 렌더링, onerror 공격 재현, 허용 목록 sanitizer, javascript: URL 차단, 안전한 하이라이트 게시판 본문, 댓글, 상품 설명처럼 사용자가 입력한 내용을 화면에 보여 주는 기능은 웹 서비스 어디에나 있습니다. 이때 가장 주의해야 할 보안 문제가 XSS(Cross-Site Scripting)입니다. 공격자가 입력한 문자열 안의 스크립트가 다른 사용자의 브라우저에서 실행되면, 로그인 토큰 탈취, 화면 위조, 원치 않는 요청 전송 같은 피해가 생깁니다. React는 기본적으로 XSS에 강합니다. JSX에 넣은 문자열은 모두 자동으로 이스케이프되기 때문입니다. 하지만 HTML 문자열을 그대로 렌더링해야 하는 경우에 사용하는 dangerouslySetInnerHTML은 이 보호를 우회합니다. 이름에 dangerously가 붙은 이유가 바로 이것입니다. 이번 글에서는 React의 자동 이스케이프가 어떻게 동..
[React 2026-10-07] 대량 리스트 렌더링 최적화 - 1만 개 목록의 문제점, 가상 스크롤(windowing) 직접 구현, overscan, 검색 필터와 결합, 더보기 페이지네이션 상품 목록, 로그 뷰어, 채팅 기록처럼 수천~수만 개의 항목을 보여 줘야 하는 화면은 흔합니다. 그런데 배열을 map으로 그대로 렌더링하면 항목 수만큼 컴포넌트가 실행되고 DOM 노드가 만들어지기 때문에, 첫 화면이 늦게 뜨고 스크롤과 입력이 버벅이게 됩니다. 사용자가 한 번에 볼 수 있는 항목은 화면 높이만큼, 보통 10~30개뿐입니다. 그렇다면 보이는 부분만 렌더링하면 되지 않을까요? 이것이 가상 스크롤(virtual scroll), 또는 windowing이라고 부르는 기법입니다. react-window, TanStack Virtual 같은 라이브러리가 이 기능을 제공하지만, 원리는 생각보다 간단해서 직접 구현해 볼 수 있습니다. 이번 글에서는 1만 개 목록을 그대로 렌더링했을 때의 비용을 측정하고,..
[React 2026-10-07] Context 성능 최적화 - 불필요한 리렌더링 원인, value 객체 useMemo, 상태와 dispatch Context 분리, children으로 리렌더 범위 줄이기, selector 패턴 Context는 props를 여러 단계로 내려 주지 않고도 깊은 곳의 컴포넌트에 값을 전달할 수 있게 해 줍니다. 그런데 Context를 전역 상태 저장소처럼 쓰다 보면 "값 하나 바꿨는데 화면 전체가 다시 렌더링된다"는 성능 문제를 만나게 됩니다. Context의 리렌더링 규칙은 단순합니다. Provider의 value가 바뀌면(Object.is 비교), 그 Context를 읽는(useContext/use) 모든 컴포넌트가 다시 렌더링됩니다. 컴포넌트가 value 중 일부만 사용하더라도, memo로 감싸져 있더라도 예외는 없습니다. 이번 글에서는 각 컴포넌트의 렌더링 횟수를 화면에 표시하면서 Context 때문에 생기는 불필요한 리렌더링을 직접 확인하고, 이를 줄이는 대표적인 방법들을 단계별로 적용해 ..
[React 2026-10-07] React 스타일링 방법 총정리 - style 객체 규칙, 조건부 className, CSS 변수로 동적 테마, data 속성 스타일링, React 19 style 태그 precedence와 중복 제거 React는 스타일링 방법을 강제하지 않습니다. 일반 CSS 파일, 인라인 style, CSS Modules, Tailwind, CSS-in-JS 라이브러리 등 무엇이든 쓸 수 있습니다. 그런데 어떤 방법을 쓰든 결국 기본이 되는 것은 style 속성과 className, 그리고 이 둘을 상태에 따라 바꾸는 방법입니다. 이번 글에서는 JSX에서 스타일을 다루는 기본 문법과 규칙, 상태에 따라 클래스를 바꾸는 패턴, CSS 변수를 활용한 동적 테마, data 속성을 이용한 상태 스타일링, 그리고 React 19에서 새로 지원하는 {label} );}export default function App() { const [chips, setChips] = useState(['React', ..
[React 2026-10-07] TypeScript로 React 컴포넌트 작성하기 - Props 타입, children, useState 제네릭, 이벤트 타입, useRef 타입, 제네릭 컴포넌트, useReducer 액션 타입 React 프로젝트의 대부분이 이제 TypeScript로 작성됩니다. Vite나 Next.js로 새 프로젝트를 만들면 기본 템플릿부터 TypeScript이고, React 19의 공식 타입(@types/react)도 꾸준히 개선되고 있습니다. TypeScript를 사용하면 컴포넌트에 잘못된 props를 넘기거나, 상태에 엉뚱한 값을 넣거나, null일 수 있는 ref를 그냥 사용하는 실수를 코드를 실행하기 전에 에디터와 컴파일러가 알려 줍니다. 대신 "이벤트 타입은 뭐라고 써야 하지?", "useState에 null을 넣으려면?" 같은 React 특유의 타입 작성법을 알아야 합니다. 이번 글에서는 React + TypeScript에서 가장 자주 쓰는 타입 작성 패턴을 예제로 정리합니다. 각 예제는 실제로 ..
[React 2026-10-07] React 19 Custom Elements(웹 컴포넌트) 완벽 지원 - 속성과 프로퍼티 전달 규칙, 객체/배열 props, 커스텀 이벤트 구독, ref로 메서드 호출, React 컴포넌트로 감싸기 웹 컴포넌트(Web Components)는 customElements.define()으로 직접 만든 HTML 태그(, 등)를 어떤 프레임워크에서든 사용할 수 있게 해 주는 브라우저 표준입니다. 디자인 시스템이나 사내 공통 UI를 프레임워크와 무관하게 만들 때 많이 사용됩니다. 그런데 React 18까지는 커스텀 엘리먼트를 제대로 지원하지 못했습니다. 모든 props를 문자열 속성(attribute)으로만 넘겨서 객체나 배열을 전달할 수 없었고, 커스텀 이벤트를 onXxx로 구독할 수도 없어서 ref와 addEventListener로 우회해야 했습니다. React 19부터는 커스텀 엘리먼트를 완벽하게 지원합니다(Custom Elements Everywhere 테스트 전체 통과). 이번 글에서는 React..