Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

React Expert

ASecurity

React 컴포넌트를 설계·구현·리팩터링하거나 상태 관리, useEffect 남용, 리렌더 성능, 접근성 문제를 다룰 때 사용한다. React 19 기준.

10 stars
0 votes
0 copies
0 views
Added 9/22/2026
developmentjavascriptjavareactapifrontend

Works with

cliapimcp

Security Analysis

A100/100

Scanned 9/22/2026

Install to Claude Code

$npx -y skills add LeeYudok/doksam-skills --skill react-expert --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of React Expert?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for React Expert
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/leeyudok-react-expert/badge)](https://www.skillsdirectory.com/skills/leeyudok-react-expert)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: react-expert
description: React 컴포넌트를 설계·구현·리팩터링하거나 상태 관리, useEffect 남용, 리렌더 성능, 접근성 문제를 다룰 때 사용한다. React 19 기준.
---

# react-expert

컴포넌트 코드가 대상이다. 번들러·패키지 매니저·의존성은 `frontend-build`,
디자인 토큰·컴포넌트 선택은 `doksam-ui` 가 맡는다.

이 문서는 **일반론을 적지 않는다.** 판단이 갈리는 지점, 자주 틀리는 곳, React 19 에서
바뀐 것만 담는다.

## 1. 상태는 필요한 만큼만, 있어야 할 곳에

판단 순서:

1. **props 나 기존 상태에서 계산할 수 있는가** → 렌더 중에 계산한다. `useState` + `useEffect`
   조합으로 파생값을 동기화하지 않는다. 이 패턴이 버그의 큰 축이다.
2. **여러 컴포넌트가 공유하는가** → 가장 가까운 공통 부모로 올린다. 전역 스토어는
   "여러 화면이 같은 서버 상태를 본다"가 성립할 때만.
3. **URL 에 있어야 하는가** — 새로고침·공유·뒤로가기가 의미 있으면 라우터 상태다.
   상세 화면·필터·탭이 여기 해당한다.

```tsx
// 나쁨 — 파생값을 상태로 두고 동기화
const [filtered, setFiltered] = useState<Room[]>([])
useEffect(() => { setFiltered(rooms.filter(r => r.name.includes(q))) }, [rooms, q])

// 좋음 — 렌더 중 계산
const filtered = useMemo(() => rooms.filter(r => r.name.includes(q)), [rooms, q])
```

`useMemo` 는 **측정 가능한 비용이 있을 때만**. 배열 몇 개 도는 것에 붙이면 코드만 늘어난다.

## 2. useEffect 는 "외부 시스템과 동기화"에만

effect 를 쓰기 전에 답한다: **이 코드가 맞물리려는 외부 시스템이 무엇인가?**
(네트워크, DOM 이벤트, 타이머, 구독) 답이 없으면 effect 가 아니다.

- **사용자 행동의 결과는 이벤트 핸들러에서 처리한다.** 상태를 바꾸고 그 변화를 effect 로
  감지해 후속 작업을 하는 구조는 흐름을 끊고 중복 실행을 부른다.
- **StrictMode 에서 effect 는 두 번 실행된다.** 이건 버그가 아니라 정리(cleanup) 누락을
  드러내는 장치다. 두 번 돌아 깨지면 effect 쪽을 고친다.

### 비동기 요청 취소는 필수

```tsx
useEffect(() => {
  let alive = true
  api.messages(dbRef, roomId).then(m => { if (alive) setMessages(m) })
  return () => { alive = false }
}, [dbRef, roomId])
```

빠뜨리면 대상을 연달아 바꿀 때 **먼저 보낸 응답이 나중에 도착해 화면을 덮는다**(경합).
`AbortController` 를 쓸 수 있으면 그쪽이 더 낫다 — 요청 자체를 끊는다.

### 의존성 배열을 거짓말로 채우지 않는다

린트가 요구하는 값을 빼서 "한 번만 실행"을 흉내내지 않는다. 대신 원인을 없앤다 —
함수는 `useCallback` 으로 안정화하거나 effect 안으로 옮기고, 정말 마운트 1회면
그 사실이 드러나게 쓴다.

## 3. 리스트와 key

- `key` 는 **데이터의 안정적 식별자**. 배열 인덱스는 순서가 바뀌거나 중간 삽입이 있으면
  상태가 엉뚱한 행에 붙는다.
- **컴포넌트를 초기화하고 싶을 때 `key` 를 바꾸는 것은 정식 기법이다.**
  상세 뷰에서 대상이 바뀔 때 내부 상태를 리셋하는 가장 단순한 방법이다.

```tsx
<MessageView key={`${room.id}:${jumpTo ?? 0}`} ... />
```

## 4. React 19 에서 달라진 것

- **`forwardRef` 가 필요 없다** — 함수 컴포넌트가 `ref` 를 일반 prop 으로 받는다.
  기존 코드를 일괄 변환할 필요는 없지만 새 코드에서 쓰지 않는다.
- **`use()`** 로 promise·context 를 조건부로 읽을 수 있다. Suspense 경계와 함께 쓴다.
- `useFormStatus`·`useActionState` 는 폼 제출 상태를 다룬다. 서버 액션이 없는
  SPA 에서도 쓸 수 있다.
- ref 콜백이 정리 함수를 반환할 수 있다.

**서드파티 컴포넌트에 ref 를 넘겨 특정 자식으로 스크롤하는 식의 조작은 취약하다.**
내부가 어떤 엘리먼트를 렌더하는지에 의존하기 때문이다. 이럴 땐 `data-*` 속성을 붙이고
컨테이너에서 `querySelector` 로 찾는 편이 타입·구조 양쪽에서 안전하다.

## 5. 접근성 — 구조로 강제한다

리뷰에서 지적하는 대신 **틀리기 어렵게** 만든다.

- **아이콘 전용 버튼은 `aria-label` 이 없으면 만들지 않는다.** 레이블을 필수 prop 으로 받는
  래퍼 컴포넌트를 두면 구조적으로 막힌다.
- 클릭 가능한 것은 `<button>`/`<a>`. `<div onClick>` 은 키보드·스크린리더에서 사라진다.
- 폼 입력은 `<label htmlFor>` 로 연결한다. placeholder 는 레이블이 아니다.
- 에러 메시지는 `role="alert"`.
- 포커스 링을 지우지 않는다. 디자인상 바꿔야 하면 `focus-visible` 로 대체 스타일을 준다.
- 상태를 색으로만 알리지 않는다 — 텍스트·아이콘·모양을 함께 쓴다.
- 브라우저 `confirm()`/`alert()` 를 쓰지 않는다. 데스크톱 셸(웹뷰)에서 이벤트 루프를 막아
  앱이 굳는다. 2단계 인라인 확인이나 다이얼로그 컴포넌트로 대체한다.

## 6. 위험한 렌더

- **`dangerouslySetInnerHTML` 는 기본 금지.** 꼭 필요하면 서버에서 새니타이즈하고, 그 사실을
  주석에 남긴다. 사용자 입력·외부 데이터를 그대로 넣지 않는다.
- 외부에서 온 URL 을 `href`/`src` 에 넣을 때 스킴을 검사한다(`javascript:` 차단).
- 사용자 텍스트는 JSX 텍스트 노드로 넣으면 자동 이스케이프된다 — 굳이 직렬화하지 않는다.

## 7. 에러 표면

- 서버가 주는 실패 사유를 **삼키지 않는다.** 공통 인터셉터(401 → 로그인 유도 등)를 둘 때는
  그 처리가 **적용되면 안 되는 요청**을 먼저 정한다. 로그인 요청의 401 은 "세션 만료"가
  아니라 "자격 불일치"이므로 서버 메시지가 그대로 보여야 한다.
- 사용자에게 보여줄 메시지와 로그용 상세를 구분한다.

## 8. 성능은 측정 후에 손댄다

기본은 "단순하게 쓰고, 느려지면 고친다". React 컴파일러가 도입된 프로젝트라면
수동 메모이제이션을 먼저 걷어낸다.

실제로 문제가 되는 것들:

- **리스트가 길다** → 가상 스크롤. 수백 건부터 체감된다.
- **큰 트리가 매 입력마다 리렌더** → 상태를 아래로 내리거나 입력을 지역화한다.
- **검색·필터가 매 타이핑마다 요청** → 디바운스(200~300ms). 이전 요청 취소도 함께.
- **부모가 매 렌더마다 새 객체·함수를 props 로 준다** → 자식이 memo 여도 소용없다.

## 9. 화면 및 폼 인터랙션 검증 (Playwright / 접근성 트리)

- **스크린샷 대신 접근성 스냅샷 우선**: AI 에이전트나 자동화 도구로 UI를 검증할 때, 고비용 이미지 비교보다 `aria-controls`, `aria-expanded`, `role="alert"` 등 접근성 트리(Accessibility Tree)를 기반으로 DOM 상태와 노출 여부를 판정한다.
- **접힘(Accordion/Collapsible) 영역 내 폼 상태**: `hidden` 속성으로 숨겨진 폼 필드는 DOM에 남아 있어 자동완성을 보존하지만 렌더 트리에서는 비가시 상태다. 테스트 시 버튼 트리거로 가시 상태(`isVisible`) 전환 후 제출과 에러 안내 렌더링을 확인한다.

## 10. 완료 조건

- 타입체크 통과, `any` 0건
- 파생값을 상태로 두고 effect 로 동기화하는 코드가 없음
- 모든 비동기 effect 에 취소·정리가 있음
- 아이콘 전용 버튼에 접근 가능한 이름이 있음
- 리스트 `key` 가 안정적 식별자임
- `dangerouslySetInnerHTML` 을 썼다면 근거가 주석에 있음
- 실제로 띄워서 확인함 — 렌더 결과와 콘솔 에러 없음까지

## Learned warnings

- (2026-08-23) Playwright E2E/MCP 검증 시 이미지보다 접근성 트리(`role=alert`, `aria-expanded` 등)를 확인하는 것이 토큰 효율과 판정 정확도가 높다. 접힌(hidden) 폼 영역은 가시성 토글 이벤트 후 인터랙션을 검증한다.

Attribution

LeeYudokLeeYudok
View sourceMore from LeeYudok →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

284072 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2192 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →