React에서 iframe 내부에 컴포넌트 렌더링
// react-frame-component 사용 (권장)
import Frame from 'react-frame-component'
;<Frame head={<style>{`body { margin: 0; }`}</style>}>
<MyComponent />
</Frame>
// 직접 구현: createPortal + contentDocument
function IframeRenderer({ children }) {
const iframeRef = useRef<HTMLIFrameElement>(null)
const [mountNode, setMountNode] = useState<HTMLElement | null>(null)
useEffect(() => {
const iframe = iframeRef.current
const handleLoad = () => setMountNode(iframe?.contentDocument?.body ?? null)
iframe?.addEventListener('load', handleLoad)
if (iframe?.contentDocument?.readyState === 'complete') handleLoad()
return () => iframe?.removeEventListener('load', handleLoad)
}, [])
return (
<>
<iframe ref={iframeRef} />
{mountNode && createPortal(children, mountNode)}
</>
)
}
WARNING
iframe 내부는 부모 CSS 미적용 (스타일 별도 주입 필요), 이벤트 버블링 안 됨. 단순 스타일 격리 목적이면 Shadow DOM 고려.
Jest setupFiles vs setupFilesAfterEnv - 실행 시점이 다르다.
- setupFiles: 테스트 프레임워크 설치 전. Jest 전역 객체 없음. 환경 변수, 폴리필용.
- setupFilesAfterEnv: 테스트 프레임워크 설치 후.
jest.setTimeout(), 커스텀 matcher, 전역beforeEach용.
process.env는 setupFiles에서. 모듈이 import 시점에 환경 변수를 읽기 때문에 setupFilesAfterEnv에서 설정하면 이미 늦다.
// jest.config.js
{ setupFiles: ['./jest.env.js'], setupFilesAfterEnv: ['./jest.setup.js'] }
// jest.env.js - 환경 변수
process.env.API_URL = 'http://test-api.example.com'
// jest.setup.js - Jest API 활용
import '@testing-library/jest-dom'
beforeEach(() => { jest.clearAllMocks() }) React Children - props 보고 동적으로 래핑 여부 결정
const renderChildren = (children) => {
const elements = React.Children.toArray(children)
const hasLink = elements.some(
(el) => React.isValidElement(el) && el.props.url
)
return hasLink ? children : <ul>{children}</ul>
}
// toArray는 string, number도 포함 → isValidElement 체크 필수
전직 트리: Children API → cloneElement → “compound component가 낫지 않나…”
yalc - 로컬 Node 모듈을 다른 프로젝트에서 바로 테스트. npm link보다 문제 적음 (파일 복사 방식).
npm i -g yalc
# 패키지에서
yalc publish # ~/.yalc에 저장
yalc push # 연결된 모든 프로젝트에 반영
yalc publish --push # 둘 다
# 앱에서
yalc add my-module
yalc remove my-module && npm install # 정리
watch 모드: "dev": "tsup src/index.ts --watch --onSuccess 'yalc push'"
.gitignore: .yalc, yalc.lock
React Children 재귀 순회 - 가능하지만 비추천 (496.md에 코드)
문제점:
- 암묵적 의존성: 중첩된 Tab이 동작하는지 사용자가 예측 불가
- 타입 안전성 부족: required prop 누락이 컴파일 타임에 안 잡힘
- 성능: 매 렌더마다 전체 트리 순회
// ❌ 마법처럼 동작 (예측 불가)
<Tabs>{/* 어디에 넣든 Tab 찾아줌 */}</Tabs>
// ✅ Compound Component
<Tabs.Root>
<Tabs.List><Tabs.Trigger value="a">A</Tabs.Trigger></Tabs.List>
<Tabs.Content value="a">Content</Tabs.Content>
</Tabs.Root>
React 팀도 2021년부터 Children API 사용 권장하지 않음: “Using Children is uncommon and can lead to fragile code”
라이브러리: react-children-utilities - deepMap, deepFind, deepFilter
React의 이중성: “선언형”이라면서 Children API로 명령형 트리 순회 제공. 역사적 이유 (2013년엔 Context API도 없었음).
tsconfig 핵심: target, lib, module
TypeScript (.ts)
↓
lib: 타입 체크 시 뭘 알고 있나? (Promise, Map 등)
↓
target: 문법을 얼마나 낮출 건가? (ES2020 → ?. 그대로, ES2019 → 삼항연산자로)
↓
module: import/export를 뭘로? (CommonJS → require, ESNext → import)
↓
JavaScript (.js)
target vs lib 분리 이유: 문법(syntax)과 API(runtime)는 다름
?.→ target이 변환 (문법)Promise→ 폴리필이 해결 (API)
{
"target": "ES2019", // 하위호환 (optional chaining 이전)
"module": "ESNext", // 트리쉐이킹 가능
"lib": ["ES2020", "DOM"], // 타입은 넉넉하게
"moduleResolution": "Node"
}
CAUTION
TS 버전 올리면서 target 그대로 두면 Webpack4 같은 구형 번들러에서 파싱 실패할 수 있음.
MDIR 스타일 인터페이스 개발 - SQLite DB를 탐색하는 도구
- Neovim Telescope 순수 Neovim 솔루션.
:StoryBrowse,:StorySearch - VS Code 확장 Activity Bar + Tree View + Quick Pick
- Bun Single-file Executable
--compile로 DB + 웹서버 + 프론트엔드 단일 파일 (~100MB)
TypeScript 중첩 객체 타입 부분 수정
interface O {
actions: { a: string; b: number }
}
// 중첩 속성 Optional로 변경
type MakeNestedOptional<T, K extends keyof T, OK extends keyof T[K]> = Omit<
T,
K
> & {
[P in K]: Omit<T[K], OK> & Partial<Pick<T[K], OK>>
}
type Result = MakeNestedOptional<O, 'actions', 'b'> // { actions: { a: string; b?: number } }
// 중첩 속성 타입 오버라이드
type OverrideNested<T, K extends keyof T, Override> = Omit<T, K> & {
[P in K]: Omit<T[K], keyof Override> & Override
}
type Result2 = OverrideNested<O, 'actions', { b: boolean }> // { actions: { a: string; b: boolean } }
한두 군데만 쓸 거면 그냥 손으로 타입 작성이 더 명확함. 유틸리티 타입은 반복 사용할 때만 가치.
// 라이브러리 객체 변이 주의
// ❌ info.actions.onDownload = undefined
// ✅ const modifiedInfo = { ...info, actions: { ...info.actions, onDownload: undefined } } 증기 계란 조리기: 계란이 많을수록 물을 적게 넣는 이유
계란 1개 (완숙): 117ml
계란 6개 (완숙): 96ml
증기 조리 방식은 물의 양 = 조리 시간. 계란이 많으면:
- 서로 열을 공유/유지 (“집단 난방” 효과)
- 증기가 좁은 공간에 집중되어 효율 ↑
- 열 손실 표면적이 상대적으로 ↓
물에 삶는 것과 달리, 증기 조리는 배치 밀도에 따라 열 효율이 크게 달라짐.
styled-components에서 &-header 같은 BEM 스타일 자식 선택자를 HTML에서 참조하는 방법? 없다.
// ❌ 해시된 클래스명과 매칭 안됨
const Container = styled.div`
&-header { color: red; }
`
// ✅ 방법 1: 일반 클래스 선택자
const Container = styled.div`
.header { color: red; }
`
<Container><div className="header">Header</div></Container>
// ✅ 방법 2: Styled 컴포넌트 변수로 선언 (추천)
const Header = styled.div`color: red;`
const Container = styled.div`
${Header} { margin-bottom: 20px; }
`