목록전체 글 (115)
기술 블로그
반응형 UI를 만들다 보면 데스크톱에서는 멀쩡한데 실기기에서만 어긋나는 문제를 마주하곤 합니다. 최근 메인 페이지의 sticky 탭바가 실기기 아이폰에서만 스크롤을 한 박자 늦게 따라오는 현상을 겪었습니다. 크롬 개발자도구의 모바일 에뮬레이터에서도 재현되지 않아 원인을 좁히기가 쉽지 않았고, 가설을 두 번 세워 두 번 다 기각당한 끝에 전혀 다른 파일의 공통 mixin 한 줄에서 범인을 찾았습니다.이번 포스트에서는 그 과정을 브라우저 렌더링 엔진의 관점에서 정리합니다.1. 현상 및 재현 조건메인 페이지의 '성공 레퍼런스' 섹션에는 모바일에서 상단에 고정되는 탭바가 있습니다. 사이트 헤더(높이 60px) 바로 아래에 붙고, 스크롤로 헤더가 숨으면 그 빈자리로 올라오는 구조입니다..tabBarSticky {..
[React] 대규모 데이터 편집 시 발생하는 입력 지연 분석: Fiber 트리 순회와 브라우저 ReflowReact 환경에서 수천 건의 데이터를 동시에 다루는 편집 UI를 구현하다 보면, 단순한 최적화만으로는 해결되지 않는 성능 병목을 마주하곤 합니다. 최근 약 3,800건의 매출 데이터를 수정하는 모달에서 입력 시 약 5초간의 지연(Input Lag)이 발생했던 사례를 통해, React 내부 동작과 브라우저 렌더링 엔진의 관점에서 그 원인을 분석하고 해결 과정을 기록합니다.1. 현상 및 초기 진단규모: 약 3,822행 (행당 Input 및 SelectBox 등 10여 개의 컴포넌트 포함)문제: 특정 입력 필드에 타이핑 시 화면이 수 초간 프리징됨.초기 가설: 검색 필터링 로직의 부하 혹은 부모 컴포넌..
정산 시스템의 데이터 수정 모달에서 최대 5,000건의 행을 테이블로 보여줘야 하는 기능을 구현했습니다. 개별 체크박스 토글은 문제가 없었으나, 헤더의 '전체 선택'을 클릭할 때마다 화면이 수 초간 멈추는 성능 저하가 발생했습니다.지난 포스트에서 다룬 Set 기반 최적화와 React.memo만으로는 해결되지 않았던 이 문제를 가상화(Virtualization)를 통해 해결한 과정을 정리합니다.1. 병목 지점 분석: React.memo가 무력화되는 순간개별 체크박스 토글은 React.memo로 최적화가 가능합니다. 5,000개 행 중 상태가 변하는 행은 단 1개뿐이기 때문입니다. 하지만 '전체 선택'은 이야기가 다릅니다.전체 선택 시 발생하는 일selectedSeqs 상태가 0개에서 5,000개로 변경됩니..
[react] 대량의 체크박스(5,000건) 렌더링 최적화하기프로젝트를 진행하다 보면 대량의 데이터를 다뤄야 하는 상황을 마주하곤 합니다. 최근 정산 데이터 수정 모달에서 약 5,000건의 데이터를 테이블로 렌더링하고, 각 행을 체크박스로 선택하는 기능을 구현했습니다.하지만 구현 후 테스트 과정에서 체크박스를 클릭할 때마다 1~2초 수준의 심각한 지연이 발생했습니다. 이번 포스트에서는 배열 기반 상태 관리의 함정과 이를 Set 및 React.memo로 해결한 과정을 정리합니다.1. 문제 상황과 원인 분석처음에는 일반적인 방식인 배열(Array)을 사용하여 선택된 아이템의 상태를 관리했습니다.const [selectedItems, setSelectedItems] = useState([]);// 개별 선택 ..
프로젝트 규모가 커짐에 따라 서버 부하를 줄이기 위해 전체 데이터를 클라이언트에서 관리하며 필터링해야 하는 경우가 많아집니다. 특히 한국어 서비스에서는 사용자의 검색 경험을 결정짓는 '초성 검색'과 UI의 안정성을 보장하는 '포탈(Portal) 렌더링'이 필수적입니다.이번 포스트에서는 hangul-js를 활용하여 검색 효율을 높이고, 외부 환경에 영향을 받지 않는 독립적인 LocalAsyncSelectBox를 구축한 과정을 정리합니다.1. 커스텀 컴포넌트 구현의 필요성기존 오픈소스 라이브러리들은 범용성을 위해 설계되었으나, 다음과 같은 기술적 제약이 있었습니다.한글 검색 최적화 미흡: 단순 텍스트 매칭만 지원하여 초성 검색 등 한국어 특화 기능을 별도로 구현해야 함.레이아웃 간섭: 드롭다운 UI가 부모 ..
1. 상태가 다른 상태를 바꾸는 패턴 (useEffect 안에서 setState)const [a, setA] = useState(0);const [b, setB] = useState(0);useEffect(() => { setB(a * 2);}, [a]);문제: 다른 값으로부터 계산 가능한 값을 굳이 상태로 두면 무한 루프 위험 + 중복 관리 필요해결: 계산은 상태로 두지 않고 직접 계산const [a, setA] = useState(0);const b = a * 2; // 혹은 useMemo2. 상태를 지나치게 잘게 나눈 경우const [email, setEmail] = useState('');const [isValid, setIsValid] = useState(false);문제: 서로 연결된 값이 ..
