본문 바로가기

Frontend

(12)
prev와 batch를 통한 상태 업데이트 React로 상태를 업데이트하다 보면 한 번쯤 이런 코드를 써본 적이 있을 것이다.setState(state + 1);setState(state + 1); 두 번 더했으니까 2가 오르겠지? 라고 기대하지만, 실제로는 그렇지 않은 경우가 많다.이 글에서는 React의 batching(배칭) 특성과 그로 인해 생기는 stale state 문제, 그리고 이를 해결하는 함수형 업데이트(prev) 패턴을, 실무에서 겪은 필터 UI 예제를 통해 정리한다. 예제 시나리오: 필터 자동 선택 + 자동 pin다음과 같은 필터 리스트가 있다고 하자.type Filter = { id: number; label: string; selected: boolean; pinned: boolean;};const initialFi..
표출할 데이터가 많은 경우 drag 버벅거리는 이슈 React Flow로 캔버스에서 테이블 컴포넌트를 드래그 하는 기능을 구현했다. 데이터가 없이 빈 컴포넌트를 드래그 하는데 아무 문제가 없었다. 그런데 데이터가 조금만 많아져도 드래그 시 성능 문제가 드러났다. 노드를 드래그할 때 마우스 커서는 잘 움직이는데, 노드는 몇 박자씩 늦게 따라오고 있었다. 즉, 드래그 속도가 크게 버벅이는 문제가 있었다. 원인: 빈번하게 렌더되는 무거운 컴포넌트노드 하나가 통째로 무거운 DOM 덩어리였다. 테이블 컴포넌트는 대략 이런 구조였다. {rows.map((row, rowIndex) => ( {columns.map((column) => ( {formatCellValue(row[column.field])} ..
key로 컴포넌트 안의 state를 초기화 하기 React는 렌더링 시점마다 Virtual DOM을 비교해서 변경된 부분만 업데이트한다. 이때 React는 이 컴포넌트가 이전에 있던 그 컴포넌트인가를 판단해야 하는데, 그 판단 기준 중 하나가 key다. 일반적으로 key는 리스트 렌더링에서 아이템을 고유하게 식별하는 용도로 많이 쓰인다. 하지만 key는 리스트 외에도 컴포넌트의 정체성을 강제로 바꾸는 트리거로 사용할 수 있다. 즉, key가 바뀌면 React는 기존 컴포넌트를 같은 것으로 보지 않고, 완전히 다른 새 컴포넌트로 취급한다. 따라서 key가 바뀌는 순간 React는 다음을 수행한다.기존 컴포넌트를 unmount한다.새로운 컴포넌트를 mount한다.그 과정에서 내부 state는 모두 초기화된다.useEffect 등 라이프사이클 로직도 다시 ..
React Query에서 두 번째 요청이 더 빠르게 느껴지는 이유 컴포넌트를 클릭하면 데이터를 요청하는 UI를 구현하면서 같은 컴포넌트를 클릭해도 첫 번째 클릭과 두 번째 클릭의 체감 속도가 완전히 다르다는 점을 알게 되었다.첫 번째 더블클릭: 로딩 스피너만 돌고, 로딩 스피너 뒤의 화면은 텅 비어 있다가 나중에 데이터 등장같은 항목을 다시 더블클릭: 스피너는 계속 도는데, 스피너 뒤에 이전 데이터가 먼저 보이고 곧 최신 데이터로 갱신됨 React Query의 상태: isLoading vs isFetchingReact Query는 로딩 단계를 두 가지로 나눈다.isLoading: 캐시에 데이터가 없어 처음 로딩 중이다.isFetching: 데이터는 있지만, 최신화를 위해 백그라운드 요청 중이다. 첫 번째 요청에서의 상태isLoading: trueisFetching: t..
React-Arborist 트리에서 한글 입력 오류 해결 react-arborist로 트리 편집 UI를 구현할 때 한글 입력 시, ㅇ 같은 초성이 중복 입력되거나 스페이스가 입력되지 않는 문제가 발생했다. 문제 원인1. 키 이벤트 버블링으로 트리 단축키가 개입한다.react-arborist는 space, arrow 등을 트리 토글/이동 단축키로 사용한다. 입력 필드에서 발생한 키 이벤트가 상위(Tree)로 버블링되면 공백 입력 대신 트리 동작이 실행된다. 스페이스가 안 찍히거나 포커스가 의도치 않게 움직인다. 2. Controlled Input이 부모 리렌더를 유발해 IME 조합을 끊는다.입력값을 부모 상태에 직접 바인딩하면 매 키 입력마다 부모가 리렌더된다. 가상 리스트(트리 행)까지 재렌더, 리마운트되면서 커서 위치가 초기화되고, IME 조합이 중간에 끊겨..
React-Arborist 트리 UI에서 Input 포커스 문제 해결 트리 UI를 react-arborist로 만들다가 노드 이름을 수정하는 input을 띄웠을 때, 입력이 제대로 안 되는 문제를 겪었다. 한 글자를 입력하면 input에서 focus가 해제되어 더 이상 입력이 불가능했다. 처음에는 ref와 useEffect를 써서 focus()를 강제로 주는 방식으로 해결하려 했지만, 입력이 시작되면 곧바로 트리의 selection 로직이 개입해 다시 focus가 다른 곳으로 이동해 버렸다.즉, 사용자가 글자를 입력 → onChange 발생 → setDraftName() 실행 → React는 상태가 변했으니 해당 노드 컴포넌트를 다시 렌더링 → 이때 트리 내부 selection 관리 로직도 같이 실행되면서 이 노드는 여전히 선택된 상태임을 갱신하거나 selection을 유..
eslint 설정해보기 eslint 설정을 제대로 살펴본 적이 없어서 프로젝트를 시작하기 전에 파악해보려고 한다. 먼저, eslint를 테스트 할 next.js 프로젝트를 생성한다.npx create-next-app@latest eslint-test-app --typescriptcd eslint-test-app typescript에 대한 커스텀 규칙을 적용하기 위해 다음을 설치해야 한다.npm install --save-dev @eslint/eslintrc @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint.config.js를 아래와 같이 수정한다.// eslint.config.jsimport { dirname } from "path";import { file..
모노레포 구축하기 모노레포를 처음부터 다시 구축해보았다. 이전에 멘토님과 함께 프로젝트를 진행할 때는 디자인시스템과 스토리북을 모노레포로 관리했었는데, 이번에는 ui라는 워크스페이스와 그것들을 사용하는 워크스페이스를 하나의 모노레포로 관리하고자 하였다.어떤 방식이 바람직한 방식인지에 대한 고민이 있었는데, 물론 모노레포의 장점도 많지만, 서비스의 크기가 크지 않은 경우 모노레포를 적용하는 것은 오버스펙이 될 수 있다는 것을 알게 되었다. 현업에서도, 그러한 경우는 shared 폴더 안에서 관리를 하고 있었다. 모노레포란?다수의 프로젝트를 한 개의 레포지토리 내에서 관리하는 소프트웨어 개발 전략 구현 방법$ mkdir [folder name]$ cd [folder name]$ pnpm init 그러면 다음과 같은 packa..