팀 구성
개인 프로젝트
기술 스택
프론트엔드: Next.js, React Query, Zustand, Framer Motion, TailwindCSS, Zod, Lodash
백엔드: Next.js, PostgreSQL
const debounceModelMutate = useCallback(
_.debounce(saveOnModelChange, 1000),
[],
);
const onModelChange = useCallback(
(e: React.ChangeEvent<HTMLTextAreaElement>) => {
change(e.target.value);
debounceModelMutate(e.target.value);
},
[change, debounceModelMutate],
);
export default function GlobalError({
error,
}: {
error: Error & { digest?: string };
}) {
useEffect(() => {
Sentry.captureException(error);
}, [error]);
return (
<html>
<body>
<NextError statusCode={undefined as any} />
</body>
</html>
);
}
Promise.all
을 사용해 요청을 동시적으로 병렬로 처리할 수 있도록 구현했습니다.const chunkedFiles = [...chunk(files, 5)];
const promises = chunkedFiles.map(chunkedFileList =>
upLoadFiles({
chunkedFileList,
type,
documentId,
callback: () =>
setSuccessCount(prev => prev + chunkedFileList.length),
}),
);
await Promise.all(promises);
function* take<T>(iter: Iterable<T>, n: number) {
const iterator = iter[Symbol.iterator]();
while (n--) {
const { value, done } = iterator.next();
if (done) break;
yield value;
}
}
export function* chunk<T>(iter: Iterable<T>, size: number) {
const iterator = iter[Symbol.iterator]();
while (true) {
const arr = [
...take(
{
[Symbol.iterator]: () => iterator,
},
size,
),
];
if (arr.length) yield arr;
if (arr.length < size) break;
}
}
Zustand
의 store
의 값이 페이지 이동에도 초기화 되지 않는 문제를 발견했습니다.ContextAPI
를 사용해 createStore
함수에서 반환되는 StoreApi
객체를 페이지에 주입 하도록 해서 페이지 단위로 store
가 관리되도록 했습니다. 사소한 버그라도 다양한 기능과 합쳐지면 치명적인 버그가 될 수 있다라는걸 알았고, Zustand
와 Next.js
를 사용하는 Best practice
에 대해서 알게 되었습니다. 관련 블로그 게시글export function EditorStoreProvider({ children }: ChildrenProps) {
const storeRef = useRef<StoreApi<EditorStore>>();
if (!storeRef.current) {
storeRef.current = createEditorStore();
}
return (
<CounterStoreContext.Provider value={storeRef.current}>
{children}
</CounterStoreContext.Provider>
);
}
export const useEditorStore = <T,>(selector: (state: EditorStore) => T): T => {
const editorStoreContext = useContext(CounterStoreContext);
if (!editorStoreContext) {
throw Error('useEditorStore must be used within a EditorStoreProvider');
}
return useStore(editorStoreContext, selector);
};
Tags