ErrorBoundary 개선 : 에러 전달, 재시도, 그리고 AsyncBoundary까지
·
프로젝트
들어가며 기존에 사용하던 ErrorBoundary는 React 공식 문서를 참조하여 class 컴포넌트로 정의했습니다. 이때 fallback UI의 타입은 ReactNode로 선언했는데, 실제로 사용하다 보면 이 타입만으로는 해결하기 어려운 상황이 생기기 시작했습니다.특히 Next.js, TanStack Query, Suspense를 함께 사용하는 환경에서는 비동기 에러 처리의 책임을 ErrorBoundary에 위임하는 패턴이 자연스럽게 등장하는데, 이 시점부터 두 가지 한계가 드러납니다. 첫째, fallback UI에서 어떤 에러가 throw되었는지 알 수 없다는 것, 둘째, 에러가 발생한 후 동일한 요청을 재시도할 방법이 없다는 것입니다.이 글에서는 이 두 가지 문제를 어떻게 해결했는지 공유합니다. ..
브라우저에서 서버로 요청부터 응답까지 처리하는 작업 ( CORS와 preflight )
·
카테고리 없음
브라우저에서 다른 출처의 리소스를 요청할 때 적용되는 보안 정책.기본적으로 Same-Origin Policy 때문에 스크립트가 다른 도메인으로 요청을 보내는걸 브라우저에서는 제한하는데, 서버가 응답 헤더에 Access-Control-Allow-Origin 같은 값을 내려주면 특정 출처의 요청을 허용할 수 있게 됩니다.브라우저에서 요청을 차단하는 것은 아닙니다. 실제로 요청은 나가지만 브라우저에서 상황에 따라 응답을 차단하게 됩니다. 응답에서 Access-Control-Allow-Origin 헤더를 확인해서 허용과 차단 여부를 판단하게 됩니다. PreflightHTTP 요청은 단순 요청 (Simple request) / 복잡한 요청 (non-simple request)로 나뉩니다. 브라우저 보안 정책 (S..
react-beautiful-dnd로 Sortable List 구현하기
·
React
TLDR사용자가 자유롭게 정렬할 수 있는 리스트 형태의 UI를 구현하게 되었습니다. 우측에서 아이콘을 통해 사용자는 리스트의 순서를 정렬할 수 있으며, 저장버튼을 통해 서버에 반영하는 UI였습니다. 사용되는 APIDragDropContextdrag and drop을 사용하기 위해, 를 drag and drop 이벤트의 전체 라이프사이클을 관리할 수 있는 상위 컴포넌트를 감싸야합니다. 내부에 Droppable과 Draggable을 통해 동작하며, 반드시 onDragEnd 핸들러를 props로 전달해야 합니다.onDragEnd: (result) => void, 드래그 종료 시 실행되는 콜백 함수 (필수)result에는 drag와 관련된 정보가 포함되어 있음 (draggabledId, source, des..
SSR에서의 top-level await의 동작
·
Node
SSR환경에서 top-level await가 있을 때는 어떻게 동작하는지에 대해 학습한 내용 정리입니다. top-level await란?일반적인 await는 함수 바깥(최상단 스코프)에서는 사용 불가하고 async 함수 내부에서만 실행됩니다. top-level await는 비동기적으로 동작하는 ESM 환경에서 모듈 최상단에서 await를 쓰는 문법을 뜻합니다. 문제SSR환경에서 서버는 모든 JS모듈을 즉시 평가할 수 있어야 합니다. 여기서 top-level await가 모듈 내에 있다면? 해당 await가 완료되고 Promise가 반환될 때까지 서버는 대기상태가 됩니다. 이는 직관적으로 바라볼 때 사용자에게 대기 시간만큼의 로딩 시간으로 다가오고 사용자 경험이 떨어지게 됩니다.import { Page }..
[Error] matchMedia not present Error
·
짧은 글
TLDRvitest + jsdom + ... 기반의 tdd 코드를 실행하던 도중 발생한 에러 matchMedia not present... 에러와 그에 대한 해결한 방법에 대한 내용입니다. 문제 원인matchMedia API는 css에서 사용하는 것으로 익숙한 웹의 미디어 쿼리를 다루는 API입니다. 해당 API에 관련된 에러가 갑자기 발생하는 이유는 react-slick에서 matchMedia API를 사용하는데, jsdom 테스트 환경에서 해당 API를 제공하지 않았기 때문입니다.따라서 테스트 환경인 vitest.setup.ts에 matchMedia polyfill을 추가하여 해결할 수 있었습니다. 해결 코드// vitest.setup.ts...Object.defineProperty(window, ..
useEffect의 clean-up 함수 반환 ( eslint consistent-return 에러 )
·
React
개요useEffect clean-up을 작성할 때 발생하는 eslint의 consistent-reutrn 에러에 대한 내용입니다. consistent-return해당 에러는 함수의 반환 방식을 일관되어야 하는 규칙입니다. 특정 조건 ( if )에 따라 함수가 값을 return 하다가 undefined를 return 하는 듯한 일관성이 깨지면 해당 에러가 발생합니다.이 규칙을 통해 사용하는 측에서 undefined를 올지 값이 올지에 대한 타입 추론이 불안정 하고 항상 undefined를 체크해야 하는 문제를 방지할 수 있습니다. 문제가 발생했던 코드useEffect(() => { if (조건) return; ... return () => {...};}, []); useEffect clean-upus..
[React/Typescript] JSX 요소 형식에 구문 또는 호출 시그니처가 없습니다.
·
React
TLDRReact에서 Functional Component가 아닌 함수에서 하나의 property로 ReactElement를 받아서 렌더링 하려고 하다가 발생한 에러입니다. 해당 type을 React.ReactElement로 선언하고, 사용하는 곳에서 JSX 형태의 UI를 넣자, ' JSX 요소 형식에 구문 또는 호출 시그니처가 없습니다.' 에러가 발생했습니다. 코드export interface Types { UI: React.ReactElement;}...tmpFunction(); 다음과 같이 type을 선언하고 함수에 Component를 발생하니 위 스크린샷 에러가 발생했습니다. 문제해당 에러가 발생하는 이유는 React.ReactElement와 는 엄밀히 보면 다르기 때문입니다. Componen..
Cloudflare에서 성능저하가 심하게 발생한다! ( AWS EC2 + ACM + CloudFront + Route53 + WAF 로 전환하기 )
·
React
TLDR또 한 번 AWS를 활용하여 웹서버 배포하는 방법입니다. 이전에는 CloudFront를 활용하여 https 웹 서버를 배포하였지만, 여기에 중요한 이슈가 발생했습니다.Cloudflare의 속도 저하위 사진처럼 api response를 받는데 평균적으로 350ms정도 소요되었고, 이게 웹뷰 앱으로 구성된 저희 앱으로 가게 되면 비교적 네트워크 속도가 느린 모바일에서 로딩이 좀 더 길어지게 되었습니다. 유저가 이탈할 거라고 우려될 수준으로 치명적인 속도였고, 개선을 위해 코드/DB 등의 개선을 진행했으나, 저 속도저하의 본질은 Cloudflare라는 것을 뒤늦게 알게 되었습니다.Cloudflare는 CDN 서비스를 제공합니다. 전세계 각국에서 접근했을 때, 가장 가까운 edge server에서 캐시 ..
React에서 안전하게 HTML 렌더링하기: dangerouslySetInnerHTML의 대안
·
React
React에서 HTML 문자열을 렌더링해야 하는 경우가 있습니다. 이런 상황에서 dangerouslySetInnerHTML을 사용하게 되는데, 이는 보안과 성능 측면에서 여러 문제를 일으킬 수 있습니다. HTML 아무 제약 없이 그대로 출력된다는 건 XSS 공격의 위험이 있고, 사용자 입력값이 직접 DOM에 주입될 수 있어 위험합니다.또한 React의 Virtual DOM 을 우회하게 되어, 최적화되지 않고 불필요한 리렌더링을 통해 성능 저하의 원인이 될 수 있습니다 대안 : html-react-parse + DOMPurify npm install html-react-parser dompurify @types/dompurify dangerouslySetInnerHTML을 대신하기 위해 위 두 가지 라이브..
[React] 비즈니스 / 도메인 로직을 통해 코드 응집도 높이기
·
React
📚 TLDR서비스를 개발하다 보면, 새로운 기능을 만드는 만큼이나, 기존의 코드를 다시 보고 다른 사람이 짠 코드를 살펴보는 시간이 많아졌습니다. 가벼운 해커톤이나, 동아리 프로젝트처럼 기간을 정해두고 하는 프로젝트성 개발과 달리 완성을 시키고 계속 유지보수 해나가야 하는 개발을 하다 보니 '아.. 리팩토링 해야 하는데..'라는 생각이 절로 들게 됩니다. 이제 와서 생각해 보면, '컨벤션을 좀 더 꼼꼼히 할걸', '코드리뷰 할 때, 이런이런 부분에 대해서는 의견을 나눠볼걸'과 같은 생각이 들긴 하지만, 그것도 1년 정도 한 프로젝트만 개발하고 코드를 보고 또 보면서 서비스를 발전시키다 보니 느껴지는 부분이지 그때의 제가 생각조차 못할 부분이지 않나 싶기도 합니다. 여러 후회와 그 후회를 바탕으로 발전시..
[React] 뒤로가기 시 상태 유지하기 ( useNavigationType, popstate )
·
React
TLDR이번에는 Tab Navigation을 서비스를 개발하며 개선한 부분에 대해서 얘기해보려고 합니다. 그저 "탭의 상태" 에 따른 표시되는 UI가 변경되는 정도의 컴포넌트로 인식하고 있었지만, 사용자측면을 고려하고 베타테스트를 진행하면서 저 "상태"를 자연스럽게 관리하는 것에 대해 고민하고 개선한 내용과 그 로직에 대해 공유하려고 합니다. 초기 로직 : UI와 그 기능에 집중처음 개발한 Tab Navigation은 UI와 Highligt Animation 등에 더 신경을 많이 썼습니다. 다른 페이지에서도 활용 될 수 있게끔, 탭의 갯수와 상관없이 UI를 적용할 수 있게끔 고민했고, 탭의 상태는 크게 신경쓰지 않았습니다.컴포넌트의 Props를 통해 tab의 정보를 배열로 받았으며, tab navigat..
[React] 웹뷰로 연결된 Android Stuiod / IOS 에 데이터 주고받기 ( 브릿지 통신 )
·
React
TLDR웹뷰형태의 앱을 서비스하게 되니, React에서 앱으로 데이터를 주고받을 수 없을까? 하는 생각이 들었습니다. 저희 서비스에서는 웹뷰로 표시될 앱을 외주를 맡기고 앱동작이 아닌 거의 모든 UI와 상태들이 웹에서 관리되고 있었기 때문에, 데이터를 전달해서 기능과 UI를 다르게 서비스하는 기능이 필요했습니다.이번 포스팅에서는 저희 서비스에서 웹과 앱간에 데이터를 주고받기 위해 사용한 두 가지 방식에 대해 소개해드리려고 합니다. URL params웹뷰로 연결된 앱에서는, URL 을 통해 앱에 웹을 표시합니다. URL 뒤에 약속된 params에 데이터를 남긴다면 데이터를 전달하거나 그에 맞춰서 UI를 변경할 수 있습니다.저희 서비스에서 앱에서 사용자의 몇몇 액션에 따라 페이지에 팝업이 떠야 하는 경우가 ..