React Native의 Modal (3. 구조적인 성능 한계점과 해결법)
개요 Android 에서 Modal 을 쓰다 보면 코드로는 설명이 안 되는 증상들을 만난다. 모달을 열고 닫을 때 한 박자 끊긴다 모달이 뜬 직후의 첫 탭이 무시된다 모달 안에서 setState 가 일어날 때마다 버벅인다 API 응답을 모달에 반영하는 순간 프레임이
A tag-first restructuring of my frontend and React Native learning notes and retrospectives, curated on Velog (@diso592).
개요 Android 에서 Modal 을 쓰다 보면 코드로는 설명이 안 되는 증상들을 만난다. 모달을 열고 닫을 때 한 박자 끊긴다 모달이 뜬 직후의 첫 탭이 무시된다 모달 안에서 setState 가 일어날 때마다 버벅인다 API 응답을 모달에 반영하는 순간 프레임이
Maestro는 mobile.dev가 만든 모바일 UI 자동화·E2E 테스트 도구다.
개요 React Native 의 Modal 이 Android 에서 유독 무겁게 느껴지는 이유를 코드에서 찾다 보면 답이 안 나온다. 원인이 JS 쪽이 아니라 그 아래, 안드로이드가 화면을 그리는 방식에 있기 때문이다. Android 에서 ` 은 android.app
폰을 케이블로 데스크탑에 꽂아두고 Claude Code 에게 "앱이 왜 죽는지 봐줘" 라고 하면, 알아서 기기 모델과 OS 버전을 확인하고 로그를 뒤져서 크래시 원인을 찾아온다. 처음 보면 Claude Code 가 폰과 직접 통신하는 특별한 기능이 있는 것처럼 느껴진다
개요 Modal 은 React Native 가 기본으로 제공하는 코어 컴포넌트다. 현재 화면 위에 콘텐츠를 띄워 사용자의 흐름을 잠시 끊고 확인이나 입력을 받을 때 쓴다. 알림, 확인 다이얼로그, 이미지 뷰어, 짧은 폼 정도가 흔한 용도다. 이름만 보면 zIndex
개요 앞 편들에서 dev/beta/pro 세 환경을 TestFlight·Play Store까지 올리는 뼈대를 완성했다. 이번 편은 그 위에 얹는 마감 작업 세 가지를 다룬다. 환경별 아이콘·표시 이름 분리 — 한 폰에 dev/beta/pro를 깔았을 때 눈으로 구분
개요 reanimated, gesture-handler, mmkv, vision-camera 같이 네이티브 코드를 포함한 라이브러리를 다룰 때, 실무에서 반복적으로 부딪히는 것들만 추렸다. 한 줄 요약하면 "JS 패키지만 올리면 끝이 아니다. 플랫폼별 한 단계가 더
개요 AppState는 React Native가 제공하는 모듈로, 앱이 포그라운드에 있는지 백그라운드에 있는지를 알려준다. AppState.currentState는 그중에서 현재 앱 상태를 동기적으로 읽을 수 있는 정적 프로퍼티이다. 이벤트를 기다리지 않고 즉시 현
개요 출시 준비를 "스토어 심사를 통과하는가"로만 보면 절반만 보는 것이다. 실제로 문제가 되는 건 올린 뒤다. 디버그에서 멀쩡하던 화면이 릴리스 빌드에서 흰 화면이 되고, 심사에서 막히는 지점은 대부분 코드가 아니라 정책 신고 항목이며, 출시 후에 가장 아쉬운 건
개요 React Native로 앱을 만들다 보면 한 번쯤 이런 의문이 생긴다. iOS에는 UINavigationController가 있고 Android에는 Fragment와 백스택이 있는데, 왜 React Navigation은 이걸 그대로 쓰지 않고 JS에서 화면 스
1. 문제 현상 Android에서 상세 화면 상단의 헤더(뒤로가기 · 공유 등 액션 버튼이 있는 바)에서 공유하기를 누르면 OS 기본 공유 시트(시스템 바텀시트)가 올라온다. 그 시트를 닫는 순간, 헤더가 한 번 아래로 내려갔다가 다시 제자리로 튀어 올라오는 스프링 같
1. 개요 운영체제는 메모리(RAM)를 한 바이트씩 다루지 않는다. 너무 비효율적이기 때문이다. 대신 메모리를 일정한 크기의 고정된 덩어리로 잘라서 관리하는데, 이 덩어리 하나를 페이지(page)라고 부른다. 그리고 그 덩어리의 크기가 페이지 크기(page size)
개요 @gorhom/bottom-sheet로 바텀시트를 구현하다 보면, 동일한 UI/UX 요구사항임에도 BottomSheetModal과 BottomSheet 사이에 드래그 응답성 차이가 발생하는 경우가 있다. 두 컴포넌트는 내부적으로 동일한 코어를 공유하지만, 마운트
1. Preload의 핵심 원칙 프리로드하는 URL은 컴포넌트가 실제로 렌더링할 URL과 글자 단위까지 동일해야 한다. FastImage는 URL(+헤더)를 캐시 키로 쓰기 때문에, URL이 조금이라도 다르면 다른 캐시로 취급되어 프리로드가 무효가 된다. 2. 리사이
개요 모던 웹·앱에서 이미지를 다룰 때, 원본 이미지를 그대로 내려받는 경우는 거의 없다. 대신 이미지 CDN 또는 이미지 변환 서버(image transformation server)에 쿼리 파라미터를 붙여서 "내가 필요한 크기·품질·포맷으로 변환해서 내려달라"고
개요 ``만 잘 써도 대부분의 화면은 동작한다. 하지만 리스트 → 상세 화면 전환에서 이미지가 한 박자 늦게 뜨는 깜빡임, 무거운 갤러리 화면 진입 후 앱이 버벅이거나 백그라운드에서 강제 종료(OOM kill)되는 현상, 사용자 저장 공간을 잡아먹는 누적 디스크 캐시
개요 로딩 스피너, 성공 체크 애니메이션, 온보딩 모션, 좋아요 버튼의 하트 터지는 효과 — 요즘 앱에서 흔히 보이는 이런 동작들 상당수가 Lottie로 만들어진다. 이 글은 Lottie가 무엇인지부터, React Native CLI 환경에서 실제로 붙이고 제어하는
개요 React Native + Tamagui Dialog로 만든 알림 모달이 등장할 때마다 미세한 jank가 발생했다. 처음엔 모달 컴포넌트 자체가 무겁다고 의심했지만, 진짜 범인은 모달이 뜨는 그 순간 같이 발사되는 5개의 네트워크 요청이었다. 이 글은 그 원인을
React Native 가상화 리스트 성능 props 정리 — FlatList vs FlashList vs LegendList 긴 리스트의 성능 문제는 결국 "화면에 보이지 않는 아이템까지 다 그리느냐"의 싸움이다. 세 라이브러리 모두 가상화(virtualizatio
개요 최적화는 어디서 시간이 쓰이는지 분해하는 데서 시작한다. 콜드 스타트는 크게 다음 구간으로 나뉜다. 프로세스 생성 + 네이티브 초기화 — OS가 앱 프로세스를 띄우고 네이티브 런타임이 올라오는 구간이다. 앱이 직접 줄이기 가장 어렵다. JS 엔진 초기화 +
개요 물리적 iOS 기기에서 앱이 실행된 직후 Metro 번들러와의 연결이 끊어지는 현상은 기기가 Mac에서 실행 중인 Metro 서버(기본 포트 8081)와 통신하지 못할 때 발생생한다. 시뮬레이터와 달리 물리적 기기는 USB 연결만으로는 디버그 서버와 통신할 수
1. eslint-plugin-react-hooks개요 핵심 전제부터 짚는다. React Compiler는 위반을 만나면 빌드를 실패시키지 않고 해당 함수를 그대로 둔다. 즉 "skip"은 에러가 아니라 안전 후퇴(silent bailout)다. RC는 Rules o
개요 RC를 도입했을 때 수동 메모이제이션이 불필요해지는 라이브러리·기능들을 정리해보자. 결론부터 말하자면 본질은 모두 같다. RC가 인라인 객체·함수·배열을 표현식 단위로 자동 캐시하므로, 그 위에 손으로 깔던 useMemo / useCallback / React.m
1. React Compiler란? React Compiler(이하 RC)는 빌드 타임에 코드를 분석해 메모이제이션을 자동으로 삽입하는 컴파일러다. 지금까지 개발자가 손으로 깔던 React.memo / useMemo / useCallback을, 컴파일러가 데이터 흐름
1. 개요 React의 메모이제이션(React.memo, useMemo, useCallback)은 효과가 작거나 오히려 손해가 나는 경우에는 적용하지 않는 것이 정석이다. 비교 연산과 메모리 비용이 절약되는 렌더 비용을 초과할 수 있기 때문이다. 그렇다면 React
이제 android/fastlane/Fastfile이 실제로 어떤 일을 하는지 lane 단위로 뜯어본다. 앞 편에서 만든 keystore·Service Account·.env 토대 위에 드디어 진짜 빌드·업로드 코드를 얹는 단계다. 구조는 iOS 편과 거의 대칭이다.
개요 이번 편이 끝나면 다음 세 줄로 환경별 Play Store 트랙 업로드가 끝난다. 내부적으로는 각각 다음 명령을 호출한다. 이를 위해 다루는 내용은 다음과 같다. Android keystore(업로드 키) 생성과 안전한 보관 Play App Signing
이제 ios/fastlane/Fastfile이 실제로 어떤 일을 자동화하는지, lane 단위로 뜯어본다. 앞 편에서 만든 서명·환경 토대(match, .env, 인증서) 위에 드디어 진짜 빌드·업로드 코드를 얹는 단계다. 아래에서 다루는 Fastfile은 3가지 환경
이번 편이 끝나면 아래 세 줄로 환경별 TestFlight 배포가 되는 상태를 향해 간다. (세 줄이 실제로 완성되는 건 실제 빌드·업로드 lane을 붙이는 다음 편이고, 이번 편은 그걸 위한 서명·환경 토대를 만든다.) 지금은 무슨 뜻인지 몰라도 되고, "이걸 만드는
개요 - 왜 Fastlane인가 React Native CLI로 앱을 만들다 보면 "코드는 다 됐는데 스토어에 올리는 게 더 오래 걸린다"는 순간이 온다. iOS는 Xcode에서 Archive → Distribute → App Store Connect 업로드, And
개요 > 이 글을 읽기 전에 알아두면 좋은 관점 하나. RN 개발을 하다 보면 npm run android, npm run ios 정도로 앱이 폰에 뜬다. 하지만 그건 내 컴퓨터에 꽂힌 디바이스나 시뮬레이터에 개발용으로 설치하는 것이고, 스토어에 올려서 남에게 배포하
[legend-list] List height is 0 경고 정리 > WARN [legend-list] List height is 0. You may need to set a style or flex: for the list, because children are
React Native CLI 프로젝트에서 "앱 이름"은 하나가 아니다. 홈 화면에 보이는 이름, 번들 내부 식별용 이름, JS에 등록된 컴포넌트 이름이 각각 따로 존재한다. 이 셋을 구분하지 못하면 이름을 바꿔도 반영되지 않거나 앱이 아예 실행되지 않는다.
개요 Upgrade Helper는 두 React Native 버전 사이에 변경된 파일을 diff 형태로 보여주는 웹 도구이다. 공식 주소는 다음과 같다. React Native 프로젝트는 본질적으로 Android 프로젝트 + iOS 프로젝트 + JavaScript(
개요 React Native CLI 프로젝트에서 reanimated와 worklets 라이브러리를 최신 버전으로 업그레이드한 뒤, iOS 빌드가 특정 지점에서 멈춰버리는 현상이 발생했다. 빌드 로그가 한참을 멈춰 있어 "무한 대기"처럼 보이는 상황. 원인을 추적해보니
1. URL 스킴이란 무엇인가 URL의 맨 앞 scheme:// 부분이 스킴(scheme) 이다. 어떤 프로토콜/대상으로 이 URL을 처리할지 가리키는 이름표다. https는 브라우저가 처리하도록 OS에 예약된 표준 스킴이고, example:// 같은 임의의 이름은
개요 위치 기반 기능은 에뮬레이터/시뮬레이터만으로는 충분히 검증하기 어렵다. 실제 GPS 칩, 센서 퓨전, 배터리 상태, OS의 위치 권한 동작이 시뮬레이터와 다르기 때문이다. 그렇다고 매번 실제로 이동하면서 테스트할 수는 없다. 그래서 실기기에 가상(mock) GP
개요 - "온라인은 예외 상태다" 모바일에서 네트워크는 항상 불안정하다고 전제하고 설계한다. 안정적으로 고정된 위치에서 연결이 이루어지는 PC와 달리, 스마트폰은 지하철·엘리베이터·터널·해외 로밍·약한 와이파이와 연결된 케이스는 흔히 일어나는 일상이다. 때문에 앱개발
개요 React Native 앱에는 JS 캐시(TanStack Query) 외에 OS 레벨 HTTP 캐시가 추가로 존재한다. 이 글은 그 레이어가 왜 생기는지, 어떤 문제를 일으키는지, 그리고 실무에서 보통 어떻게 대응하는지를 정리한다. 1. 웹 vs 앱: HTTP
개요 RN에서 이미지 캐싱을 다루다 보면 "디코딩"이라는 단어를 계속 만나게 된다. "메모리 캐시를 비우면 다시 디코딩해서 깜빡인다", "큰 이미지 여러 장을 동시에 디코딩하면 프레임이 튄다" 같은 문장들이다. 이 디코딩이 대체 무슨 작업이고, 왜 비용이 크며, 왜
개요 react native 에서 안드로이드는 빌드할 때, dev 든 release든 매우 느린 시간을 거친다. ios는 비교적 android보다 빠른 것 같은데, 왜 유독 android의 빌드 속도는 느린걸까? ios처럼 빠르게 할 수 없는 것일까? 이에 대해 살펴보
개요 containerLayoutState는 @gorhom/bottom-sheet 바텀시트 컨테이너의 레이아웃 정보를 담는 prop이다. 시트가 어느 높이까지 펼쳐질 수 있는지, 화면 어디에 얹혀 있는지를 계산하는 기준값이다. 기존에 각각 존재하던 containe
개요 onTextLayout은 React Native `` 컴포넌트의 prop이다. 텍스트가 화면에 실제로 레이아웃(배치)될 때마다 호출되며, 각 줄(line) 단위의 위치·크기 정보를 콜백으로 전달한다. JS 측에서 미리 알 수 없는 "텍스트가 몇 줄로 나뉘는가",
개요 라이브러리나 RN 버전, 빌드 도구 업그레이드를 언제 어느 타이밍에 진행하는게 가장 Best 일지 의문을 품었다. 프로젝트를 장기간 몇개월 ~ n년 진행하면 deprecated 된 기능들이 나올텐데, 그러면 어떠한 기준을 가지고 패키지들의 버전을 점검하는지가 궁
개요 iOS에서는 hitSlop을 키우면 그대로 터치 영역이 늘어나지만, Android에서는 부모 뷰의 경계에 막혀 무시되는 경우가 있다. 이 문서는 그 원인과 우리 코드베이스에서 채택한 해결 패턴을 정리해보자. ios 와 android의 hit test 처리 방식
개요 앱이 종료될 때는 한마디로 요약하면, 앱 프로세스 종료 → JS 런타임 종료 → 힙 삭제가 일어난다. 이 과정이 실제로 어떻게 일어나는지, 그리고 이걸 실무에서 어떻게 활용하는지 알아보자. 1.핵심 전제 : "종료는 예고 없이 온다" 먼저 가장 중요한 사실부
React Native에서 비대칭 borderRadius가 만드는 한 프레임 잔상 가로 스크롤 리스트의 필터 탭을 전환할 때, 화면 좌상단으로 작은 검은 박스가 한순간 사라지는 잔상이 보였다. 원인은 리스트 라이브러리가 아니라, 한 박스에 비대칭 borderRadiu
ListEmptyComponent vs 삼항연산자 — 무엇이 다른가 FlashList, LegendList(그리고 RN 기본 FlatList)에는 ListEmptyComponent라는 prop이 있다. data가 비어 있을 때 자동으로 이 컴포넌트를 렌더링해준다. 그
React Navigation 정적 API의 Deep Linking > 대상: React Native CLI + @react-navigation/native-stack (v7, Static API) > 범위: linking이 무엇인지부터, 정적 API에서 그것이 어떻
React Native 메모리 누수 & OOM 크래시 대응 > 대상: React Native CLI + New Architecture(Hermes, JSI, Fabric) 환경 > 목표: 메모리가 새는 지점을 막고, 저사양 단말에서 OOM(Out Of Memory)
Velog GraphQL → deployment pipeline → RSC static rendering
Velog @diso592
GraphQL API
scripts/fetch-velog.ts
try/catch + exit(0)
src/data/velog-posts.json
committed seed
Next.js 16 RSC
utilFetchVelogArchive
/{locale}/writings
static HTML
A GitHub Actions cron polls the velog RSS and triggers a deploy webhook when a new post is detected.
SOURCE
velog.io/@diso592 posts + tags
FETCH
GraphQL cursor pagination on deploy
SEED
committed seed, previous JSON retained on failure
RENDER
server fs load, RSC static rendering
OUTPUT
/{locale}/writings static HTML