분류 전체보기
무한 스크롤 데이터 관리
무한 스크롤 기능을 구현할 때는 데이터의 일관성과 동기화가 중요한 문제입니다. 이번 글에서는 데이터 구조와 조회, 삭제, 업데이트, 생성 등의 상황에서 발생할 수 있는 문제와 그 해결 방안에 대해 자세히 살펴보겠습니다.데이터 구조데이터는 다음과 같은 구조를 가집니다: [ [ { item }, {} ] -> (page),... ]각 페이지는 여러 개의 아이템을 포함하고 있으며, 무한 스크롤을 통해 페이지를 순차적으로 불러오게 됩니다.조회중복 및 누락 데이터다른 사용자들이 데이터를 생성하거나 삭제하는 과정에서, 동일한 데이터를 중복해서 불러오거나 일부 데이터를 놓칠 수 있습니다.중복 데이터 처리infinite 호출 한 쪽에서 data를 리턴할 때 Set을 사용하여 중복된 데이터를 제거합니다.중복 데이터가 ..
[wake up!] dependencie, devDependencies, peerDependencies
package.json의 dependencies와 devDependencies의 차이점에 대한 정리 Peer Dependencies 에 대하여 dependencies 런타임과 빌드타임, 개발중 모두에서 이 종속성 패키지들이 필요하기 때문에, 앱이 빌드 될 때 이 종속성 패키지들이 번들에 포함되어 배포된다. devDependencies 런타임에서는 필요하지 않고 빌드타임 & 개발중에만 필요한 패키지들이다. 번들에는 포함되지 않는 종속성 패키지들이다. peerDependencies 해당 프로젝트를 운용하기 위해 항목에 포함된 의존성이 필요한 항목을 리스트하기 위해 있는 항목이다. 해당 패키지가 설치되지 않는 상태에서 어플리케이션이 실행된다면 우리의 프로젝트는 실행되지 않고 오류를 뱉는다. npm 버전 7부터..
[wake up!] bundler, babel-polyfill
bundler 번들러 비교를 통한 빌드 최적화 JS 빌드 과정 트랜스파일(Transpiling) 번들링(Bundling) 압축(Minifying) 번들러(bundler) webpack rollup parcel swc esbuild .... 초보 웹 개발자를 위한 자바스크립트 빌드 툴과 SWC 바벨(Babel)로 ES6 최신 js 문법을 트렌스파일링 하고 코드 경량화를 위해 Terser같이 mangler로 단어를 축약하고, compressor로 js코드를 압축시킨다. 여기서 모든 과정들이 시간을 할당 받게된다. build 작업 시간을 줄이고 좋은 포퍼먼스를 찾는것이 중요한 과제가 된다. => 여기서는 요즘 핫한 SWC(Speedy Web Compiler)를 소개한다. Babel로 polyfill 적용 Yo..
[wake up!] cjs, esm
cjs, esm? Dan Fabulich의 Node Modules at War: Why CommonJS and ES Modules Can’t Get Along 번역글 왜 CommonJS와 ES Modules는 함께 쓸 수 없는가 Node 14에서는 현재 두 가지 종류의 스크립트가 있다. 하나는 옛날 방식인 CJS(CommonJS) 스크립트고 다른 하나는 import와 export를 사용하는 새로운 방식의 ESM(ECMAScript Modules) 스크립트이다. ESM 스크립트에서 import와 export는 언어의 일부이다. CJS와 마찬가지로 named exports와 default export에 대한 두 가지 구문이 있다. CommonJS에서 require()는 동기적으로 동작한다. require()..
[route-type-safe] URL - 페이지 관리
URL information URL information? 이 의미는 URL 하나의 정보로 페이지를 탐색할 수 있다. 즉, URL 하나로 search 기능을 한다. history의 Location의 타입을 보면 대표적으로 pathname, search, state, hash를 볼 수 있다. history는 페이지 stack 관리로 SPA가 가능하게 끔 해주는 유용한 인터페이스다. export interface Location { pathname: Pathname; search: Search; state: S; hash: Hash; key?: LocationKey | undefined; } // /id/2#ss?sort=L&page=3 { pathname: '/id/2', search: '?sort=L&p..
[modules] React + Data fetch handling
고민하게 된 시점 나의 최대 관심사는 뷰(View)를 작업하기 위함이다. 컴포넌트의 역할은 단순히 데이터가 오면 뷰를 보여주기만 하면 된다. 하지만, 여기서 다이나믹 뷰를 위해 비즈니스 로직을 컴포넌트 공간에서 작성하게 되면, 의존성 결합이 상당하다. 오직 뷰만 작업했던 공간이, fetch("url")로 데이터 오고 가는 형태까지 작성하게 되었다. function App() { const [data, setData] = useState({ hits: [] }); const [query, setQuery] = useState('redux'); const [url, setUrl] = useState( 'https://hn.algolia.com/api/v1/search?query=redux', ); const..
[setting] Atomic Design?
Atomic Design? (원자 - 분자 - 유기체 - 템플릿 - 페이지) 아토믹 디자인이 조금 더 컴포넌트를 나눌 때 도움이 될 거라고 생각이 들었다. 하지만, 아토믹 또한 모호한 면이 생기게 되었고 LINE Entry 📹에서 아토믹 디자인을 좀 더 유연하게 쓴 사례를 보게 되어 다시 정립하게 되었다. Atom 원자 단위에서는 Button, h1과 같은 쪼갤 수 없는 단위를 말한다. 만약 CustomButton, LinkButton이 생기게 된다면 폴더를 하나로 합쳐야 할까? A: 현재는 폴더를 따로 가야하는게 맞는 거 같다 if문 같이 분기를 타고 리턴하는 것은 나중에 유지보수 시 찾기 힘들 경 우가 많을 듯하다. Molecule, Organism => Organism 분자는 Atom 2개 이상의 ..
[setting] React 컴포넌트 분리와 폴더 구조화
Preview React를 배우면서 좋았던 점은 라이브러리라는 점이다. 단점은 라이브러리라는 점이다. 프로젝트마다 특색이 다르기 때문에, 아키텍처 구성이 달라질 수 있어 프론트 작업 시 자유도가 높아질수록 해당 프로젝트의 맞게 아키텍처를 구성할 수 있었다. 하지만, 자유도가 높아짐에 따라 폴더구조와 컴포넌트 사고방식을 생각하는 시간 비용이 상당히 높았다. 처음으로 리엑트 프로젝트 도입한 시점에서는 페이지도 단순하고 리액트를 사용에만 집중을 가졌다. 하지만, 점차적으로 페이지가 늘어나고, 계속해서 컴포넌트 분리를 하고 해당 컴포넌트를 어디 폴더에 넣을지 고민이 커졌다. 이슈 처리에만 집중을 하고 싶은데 계속해서 부가적인 요인으로 나를 너무 괴롭혔다. 그래서 나만의 컴포넌트 분리 방식과 폴더 아키텍처 방식을..
[helper] Redux + Redux-saga
Preview redux는 단순히 전역 상태 관리를 위한 도구였다. 하지만 우리는 data fetch handling을 통해서 정보 저장을 많이 하기 때문에 redux-saga(middleware)와 redux 결합을 많이 이용하고 있다. (redux-toolkit에서는 crateAsyncthunk가 있다) 여기서 api 추가할 때마다, action과 fetch 상태를 만들어줘야 하는 중복 패턴이 발생하게 되어 이것을 쉽게 해결하고자 helper 함수를 제작하였다. helper/type.d.ts 전체 코드 helper에서 공통으로 사용하는 type 관리 코드 설명 import { ActionCreatorWithPreparedPayload } from '@reduxjs/toolkit'; import { F..
[setting] Next + Redux
Preview reducer, saga, store, type 설정 store/rootReducer.ts 전체 코드 reducer 여러 reducer 들을 combineReducers로 하나로 묶음 const reducer = combineReducers({ [FETCH_STATUS]: fetchStatusReducer, [USER]: userReducer, [POST]: postReducer, [HASHTAG]: hashtagReducer, }); RootState[type] redux에서 state 타입을 항상 써야 하기 때문에 import 하지 않고 global 영역으로 declare 선언 declare global { type RootState = ReturnType; } rootReducer n..