한 달 전 · 박준서 님의 새로운 댓글
리액트 프로젝트에 FSD 아키텍처 적용. 이 구성이 맞을까요?
안녕하세요. 현재 진행 중인 리액트 프로젝트에서 유지보수성과 확장성에 어려움을 느껴 폴더 구조를 Feature-Sliced Design(FSD) 아키텍처 기반으로 전면 리팩토링했습니다. 기존에는 `components/`, `pages/`, `apis/` 등 기능과 역할이 섞인 구조로 되어 있어, 코드의 위치가 불분명하고 협업에 어려움이 있었습니다. 이를 해결하고자 다양한 아키텍처를 조사한 끝에, FSD의 레이어 개념(Layers)에 맞춰 다음과 같은 방식으로 구조를 정리했습니다. - `app/`: `App.js`, `index.js` 등 프로젝트 진입점과 글로벌 설정 파일을 포함 - ` entities/`: `User`, `Article`, `CodingZone` 등 주요 도메인의 데이터 모델과 API 연동 담당 - `features/`: 로그인, 게시글 작성, 코딩존 출석 등 각 기능별로 모듈화하고, 필요한 경우 `hooks/` 등의 내부 디렉토리로 세분화 - `pages/`: 라우팅과 연결된 실제 페이지 컴포넌트 관리 (예: `CreatePage`, `EditPage` 등) - `widgets/`: 재사용 가능한 독립 UI 요소들 (예: `Footer`, `Navbar`, `Pagination` 등) - `shared/`: 공통 API, 유틸, 모달 컴포넌트 등 여러 기능에서 공유되는 요소들을 배치 기능 중심의 구조로 바꾸면서, 각 요소의 역할이 명확해지고 코드 탐색 및 유지보수가 훨씬 쉬워졌습니다. 현재는 복잡한 비즈니스 로직이 없어 `processes/` 레이어는 생략했지만, 추후 워크플로우가 필요한 기능이 생긴다면 도입할 계획입니다. 제가 구성한 이 폴더 구조와 레이어 분리가 실제 FSD 아키텍처 가이드에 부합하는 방향인지, 혹시 보완하거나 개선할 부분이 있다면 조언을 구하고 싶습니다. 자세한 내용은 블로그에 정리해 두었습니다. 👉 [https://juncci.tistory.com/4](https://juncci.tistory.com/4) 읽어주셔서 감사합니다!
개발자
#fsd
#react
#refactory
#프론드엔드
#폴더구조
답변 1
댓글 1
조회 131
일 년 전 · 삭제된 사용자 님의 댓글 업데이트
안녕하세요.. 정말 이것저것 다 해봤는데 안되네요 ㅠ
안녕하세요. 리액트와 리액트 쿼리를 이용해 프로젝트를 진행 중 입니다. 저는 일단. src/hooks/useProduct.jsx 라는 커스텀 훅 을 만들었습니다. 제 계획은 1. 맨 처음 최상단 Home.jsx 에서 useProduct 라는 커스텀 훅 호출 2. 자식컴포넌트에 data를 전달 3. Search.jsx에서 받은 filter값으로 커스텀 훅 안의 query 재실행 4. 바뀐 상태는 Home.jsx 가 다시 받고 자식 컴포넌트에게 전달. 1~3까지는 콘솔찍어가면서 잘 되는데 4.는 되지 않습니다. (쿼리 데이터가 바뀌어도 4이 재 실행이 안됨..) ㅠㅠㅠㅠㅠㅠㅠ 쿼리 옵션도 줘보고 전역 상태도 만들어보고 이것저것 다 해봤는데 ㅠㅠ 혹시 아시는분 계신가요..? 어떠한 답변도 정말 감사히 받겠습니다 간략 코드첨부) Home.jsx const Home = ()=>{ const { data, error, isLoading } = useProduct(); return ( <Search /> <List data={data?.product} /> ); }; export default Home; Search.jsx const Search = () => { ```일부코드생략``` const { updateQuery } = useProduct (); const handleSubmit = () => { const searchData = { productId }; updateQuery(productId); }; } return( ```일부코드생략``` <button onClick={handleSubmit}> 조회 </button> ) } export default Search; useProduct.jsx const useProduct = () => { const [queryData, setQueryData] = useState(); const { data, error, isLoading } = useQuery({ queryKey: ["product", queryData], queryFn: () => fetchProduct(queryData), }); const updateFilters = (queryData) => { setQueryData(() => (queryData); }; return { data, error, isLoading, updateQuery , }; export default useProduct ;
개발자
#react
#react-query
#react-query-v5
답변 3
댓글 6
조회 116
일 년 전 · 예빈 님의 새로운 댓글
타입스크립트 타입지정
리액트 쿼리로 OptimisticUpdate 를 구현했는데 onError 에서 context 타입 지정을 어떻게 해야할지 모르겠습니다 ㅠㅠ context : 타입 하면 오류나고, data : 타입 = context 해도 오류나고 as 를 쓰면 해결되긴 하는데 더 좋은 방법 없을까요? ㅠㅠㅠ 'use client'; import { useState } from 'react'; import { toast } from 'react-toastify'; import { usePostLikeCount } from '@/hooks'; interface LikeContextType { previousLikeCount: number; previousIsLike: boolean; } export const useOptimisticLike = ( boardId: number, initialLikeCount: number, initialIsLike: boolean, refetch: () => void ) => { const [optimisticLikeCount, setOptimisticLikeCount] = useState(initialLikeCount); const [optimisticIsLike, setOptimisticIsLike] = useState(initialIsLike); const { mutate: postMutate } = usePostLikeCount(boardId, { onMutate: async (): Promise<LikeContextType> => { setOptimisticLikeCount((prev) => optimisticIsLike ? prev - 1 : prev + 1 ); setOptimisticIsLike((prev) => !prev); return { previousLikeCount: optimisticLikeCount, previousIsLike: optimisticIsLike, }; }, onError: (err, variables, context) => { const data: LikeContextType = context; if (data) { setOptimisticLikeCount(data.previousLikeCount); setOptimisticIsLike(data.previousIsLike); } toast.error('좋아요 업데이트에 실패했습니다.'); }, onSuccess: () => { refetch(); }, }); const uploadLike = () => { postMutate(); }; return { optimisticLikeCount, optimisticIsLike, uploadLike, }; };
개발자
#react-query
#typescript
답변 1
댓글 1
조회 60
일 년 전 · 유길종 님의 답변 업데이트
비지니스로직 분리 질문드려요!
사이드 프로젝트를 완료했고 비지니스로직을 분리하고 싶습니다 hooks라는 폴더를 만들어 action과 api로 나눠 action에는 파이어베이스를 사용하기에 여러가지 행동적인 함수 ( 좋아요 기능, 글쓰기 기능, 조회수 등등) Api에는 탄스택쿼리를 사용하기에 해당되는 쿼리 로직들을 나눌려고 합니다. 훅을 사용하는것처럼 하나의 파일에 하나의 로직을 담아야하나요? 아니면 비슷한것끼리 파일에 넣고 export로 여러개를 두어야하나요? 제 스타일대로 하면 될꺼 같지만 현업에서는 어떤식으로 비지니스 로직을 분리하고 관리하는지 궁금해요 TMI. 로그인 페이지 하나 적용해봤는데 코드가 완전 깔끔하고 이컴포넌트에서 무엇을 하는지 딱 보여서 좋네요!!
개발자
#react
답변 1
댓글 1
조회 440
일 년 전 · 김인후 님의 새로운 답변
리액트에서 컴포넌트 내부 함수 위치
리액트로 컴포넌트를 작성하다보면, 해당 컴포넌트에서만 사용되는 함수나 hook이 생기게되는데요. 이 함수들이 너무 길어지면, 별도 파일로 분리하고 싶다는 생각이 강하게 드는 것 같습니다.. utils에 두기에는 유틸이라고 하기엔 너무 이 컴포넌트와 밀접하게 연관되어있어서 조금 아쉽고, hooks에 두기에는 공용으로 사용될 것도 아닐뿐더러 이렇게하면 과도하게 hooks가 많아져서 아쉽고.. AComponetFuncs라고 하기엔 또 애매하고.. 고민이 많아지네요. 관련해서 조언이나 찾아보면 좋을 키워드 추천 부탁드립니다. 다들 어떻게 파일로 분리하시나요?
개발자
#react
답변 1
댓글 0
조회 163
일 년 전 · 김태우 님의 답변 업데이트
모바일 뷰에서 팝업이, 뒤로가기 제스처를 취했을 때 이전 페이지로 넘어가지 않고 팝업만 닫히게 구현하고 싶어요.
안녕하세요. 이번에 웹뷰 뿐만 아니라 모바일 뷰까지 같이 개발을 진행하고 있는데, 팝업의 기능 구현에 어려움을 겪고 있어 질문을 남깁니다. 웹뷰 같은 경우는 바로 팝업을 닫을 수 있지만, 모바일 같은 경우에는 무심결에 뒤로가기 제스처를 통해서 팝업을 닫으려는 유저가 있을 수 있다고 생각합니다. 그래서 뒤로가기 제스처가 발동 시, 이전 페이지로 렌더링을 시도하는 것을 막고 해당 팝업을 unmount 시키고 싶은데 방법이 잘 생각나지 않네요. **개발환경은 프론트 (react) 입니다. 그냥 간단하게 생각한다면 모바일 뷰일 때를 dom 으로 감지 후에 해당 팝업이 mount 된 상태에서 navigation(-1) 같은 동작을 감지하여, 이전 페이지로 이동 대신 팝업을 unmount 시키게, useEffect 등으로 감시하면 될 것 같은데, 어떻게 구현해야 될까요? + 현재 react-router-dom v6.2를 사용하고 있는데, useBlocker를 활용하면 해결될 것 같습니다..! https://reactrouter.com/en/main/hooks/use-blocker
개발자
#react
#웹앱
#모바일앱
#팝업
#react-router-dom
답변 1
댓글 0
조회 629
2년 전 · 허니 님의 새로운 답변
(SSR 새로고침 문제)NextJS page에서 redux persist gate 설정하면 Client컴포넌트로 인식되는 문제
NextJS Pages Router에서 유저 데이터를 상태관리하기위해 redux를 사용했으나, 새로고침 시 데이터가 날라가는 문제를 해결하기 위해 persist gate를 사용했습니다. 하지만 redux persist gate를 사용하면 클라이언트 컴포넌트로 인지되는 문제가 있습니다. 궁금한 것 1) persist gate를 잘못써서 생긴 문제일까요? 아님 persist gate를 쓰면 안될까요? 2) 해결 방법으로 생각 해본 것은, "persist gate를 사용하지 않고 매 새로고침 시 저장되어있는 local storage에서 데이터를 새로 가져온다." 입니다. 3) ssr시 상태관리 새로고침 다른 방법으로 해결해본 경험 있으시면 아무렇게나 대답해주시면 감사하겠습니다!!! ----------------------------------------------- 문제의 코드 위치: https://github.com/bbookng/zippyziggy-v2/blob/main/frontend/zippy-ziggy/src/pages/_app.tsx 문제의 코드: import GlobalStyle from '@/styles/Global.style'; import useDarkMode from '@/hooks/useDarkMode'; import { media } from '@/styles/media'; import { darkTheme, lightTheme } from '@/styles/theme'; import type { AppProps } from 'next/app'; import { ThemeProvider, createGlobalStyle } from 'styled-components'; import normalize from 'styled-normalize'; import '@/styles/index.css'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import AppLayout from '@/layout/AppLayout'; import store, { persistor } from '@/core/store'; import { PersistGate } from 'redux-persist/integration/react'; import { Provider } from 'react-redux'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import 'toastify-js/src/toastify.css'; import { ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; import DefaultHead from '@/components/Head/DefaultHead'; import Construction from './construction'; const queryClient = new QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: false, // default: true }, }, }); function App({ Component, pageProps }: AppProps) { const { colorTheme, toggleTheme } = useDarkMode(); return ( <Provider store={store}> <PersistGate persistor={persistor}> <QueryClientProvider client={queryClient}> <ThemeProvider theme={colorTheme === 'dark' ? darkTheme : lightTheme}> <AppLayout toggleTheme={toggleTheme}> <Component {...pageProps} /> ... </AppLayout> </ThemeProvider> <ReactQueryDevtools initialIsOpen={false} /> </QueryClientProvider> </PersistGate> </Provider> ); } export default App;
개발자
#next.js
#persis
#redux
답변 1
댓글 0
조회 570
2년 전 · 박예진 님의 새로운 댓글
채팅 기능 client 가 null 값이 돼요
하나의 페이지에서 connectHandler를 작동하고 또다른 페이지에서 sendHandler를 작동하려고 하는데 이렇게 해서는 useChat()이 리렌더링 되면서 client 값이 초기화가 되더라구요 값을 유지하고 싶고 recoil에 client를 담는 건 불가능이라고 떠서... connectHandler와 sendHandler를 다른 hooks로 분리하는 방법도 생각해봤는데 그러면 또 client값이 connect한 값이 아니더라구요 무슨 방법이 있을까요? 제발 도와주세요 ㅠㅠ (한 페이지에서 connectHandler, sendHandler, disconnectHandler 실행하면 잘 작동합니다!) import { CompatClient, Stomp } from "@stomp/stompjs"; import { useRef } from "react"; import { useRecoilState } from "recoil"; import { inputMessageState, messageState } from "../../states/chatting"; export function useChat() { const [messages, setMessages] = useRecoilState(messageState); const [inputMessage, setInputMessage] = useRecoilState(inputMessageState); const token = localStorage.getItem("accessToken"); // 채팅 연결 구독 const client = useRef<CompatClient>(); const connectHandler = () => { client.current = Stomp.over(() => { const sock = new WebSocket("wss://m-ssaem.com:8080/stomp/chat"); return sock; }); client.current.connect( { token: token, }, () => { client.current && client.current.subscribe(`/sub/chat/room/1`, onMessageReceived, { token: token!, }); }, ); }; const onMessageReceived = (message: any) => { setMessages((prevMessage) => [...prevMessage, JSON.parse(message.body)]); }; // 채팅 나가기 const disconnectHandler = () => { if (client.current) { client.current.disconnect(() => { window.location.reload(); }); } }; // 채팅 보내기 const sendHandler = () => { if (client.current && inputMessage.trim() !== "") { client.current.send( `/pub/chat/message`, { token: token, }, JSON.stringify({ roomId: 1, message: inputMessage, type: "TALK", }), ); setInputMessage(""); } }; return { connectHandler, disconnectHandler, sendHandler, }; }
개발자
#react
#chatting
#stompjs
답변 1
댓글 8
조회 238
2년 전 · 엄홍재 님의 새로운 답변
리액트 혹은 next.js 환경에서 모달을 관리하는 방법이 궁금합니다.
안녕하세요. 프론트엔드 개발자가 되기 위해 공부중인 취준생입니다. 사이드 프로젝트를 하면서 많은 모달들을 만들어 왔었는데요. 문득 몇가지의 궁금한 점이 생겨서 현업 분들은 어떤식으로 작업하시는지 궁금해서 여쭙습니다. 1. 여러개의 모달의 오픈 유무를 전역 상태에서 한번에 관리 하는 방법이 좋을까요? 아니면 열고 닫을때 필요한 state와 함수를 custom hooks로 만들어서 컴포넌트 내에서 state와 props로 관리 하는게 좋은가요? 2. 전역 관리를 선택했을시, 모달을 켜둔 채로 뒤로가기 혹은 앞으로가기 후에 다시 본래 페이지에 되돌아오면 모달이 켜진 상태로 유지가 됩니다. 이런 경우는 어떤 식으로 처리를 하시는 편인가요? 뒤로가기 버튼에 모달을 false로 바꾸는 이벤트를 추가하는 방법일까요? 답변 기다리고 있겠습니다~
개발자
#모달
#modal
#react
#next.js
답변 2
댓글 0
조회 539
2년 전 · 김재성 님의 새로운 답변
전역 redux 값 사용 관련 질문 있습니다.
안녕하세요! 리덕스를 쓰는 이유에 대해서 궁금한 점이 생겨서 질문드립니다. 작은 프로젝트에서는 정보를 저장하는 데 hooks과 props를 사용해도 문제가 없는 것 같은데 리덕스 스토어에 모든 값을 전역값으로 저장하면 프로젝트가 무거워지는 것 같습니다. axios통신, 데이터 저장과 상태관리에 리덕스를 사용하면 좋은 점이 뭐가 있을까요? props drilling을 막고, 버튼 같은 하위 컴포넌트에서 바로 사용할 수 있는 장점이 있다고 알고 있습니다.
개발자
#redux
#hook
#props
답변 1
댓글 0
조회 158
2년 전 · 달레 님의 답변 업데이트
input form 데이터 땡겨올 때 useRef를 많이 사용하지 않는 이유가 있나요?
회원가입 폼에 input에 useRef로 값 땡겨오면 값이 변할 때 재랜더링이 없어서 좋을 것 같은데 깃헙 다른 분들 코드 보면 거의 Hooks으로 useInput 써서 하는데 무슨 이유로 더 간단한 useRef를 안 쓰고 기존 onChage 형식으로 하는 건가요?
개발자
#react
#input-form
#useref
#hooks
답변 1
댓글 0
추천해요 1
조회 496
2년 전 · 커리어리 AI 봇 님의 새로운 답변
jest환경에서의 export * from './*' 이슈
안녕하세요 react native로 테스트코드를 짜다가 막힌 개발자입니다 저는 주로 hooks라는 폴더가 있으면 그 안에 index.ts를 만들어서 이와 같은 레이어의 폴더,파일들을 전부 export * from './*' 하여 실제로 사용할때 import { someHook } from 'hooks' 이렇게 사용하고 있었습니다. 구현 및 동작에는 오랫동안 이슈가 없었지만 이번에 유닛테스트를 도입하면서 jest가 'hooks'라는 놈을 import하는 파일을 테스트할 시 그 안에 모든 파일들을 읽어서 테스트실패가 아닌 jest에러를 계속 만나고 있습니다.. 노가다 mocking을 하여 어느정도 막았지만 테스트할 파일이 아닌 파일에서 계속 에러가 등장해서 babel과 jest의 config를 계속 수정해봤지만 해결이 되지않아 이렇게 자문을 구합니다. 추가로 웹에서도 이러한 export * 을 사용한 index.ts패턴을 사용할 때 성능 등의 이슈가 없는지 궁금합니다!
개발자
#jest
#babel
#javascript
#react-native
답변 1
댓글 0
추천해요 1
보충이 필요해요 1
조회 74
2년 전 · kevin 님의 답변 업데이트
react Custom Hook을 만들려고 하는데 도움이 필요합니다ㅠㅠ
안녕하세요, react, typescript로 개발중인 주니어 취준생입니다 커스텀 훅을 처음으로 작성해보려고하는데... 제가 커스텀 훅에 대한 이해가 부족한 건지 이런 저런 방법을 사용해봐도 같은 에러가 계속 나네요ㅠㅠ vscode상에서 나타나는 에러는 없는데 로그아웃 버튼을 누르면 콘솔에 계속 같은 에러가 생깁니다...! 상황) 로그아웃 로직을 재사용할 수 있게 커스텀 훅으로 관리하려고 함 [로그아웃 로직] - 로그아웃 하면 localStorage의 access_token과 refresh_token을 삭제하고, - alert창을 띄우고, 메인화면으로 이동하게 함. 에러메세지에 있는 링크 https://reactjs.org/warnings/invalid-hook-call-warning.html 에 있는 세가지 일반적인 이유는 아래와 같습니다. 1. React와 React DOM의 버전이 일치하지 않을 수 있습니다 . -> 확인해보니 Hooks를 지원하는 버전 맞습니다. 2. Hooks 규칙을 위반하고 있을 수 있습니다 . -> Hooks규칙을 맞춰서 작성했다고 생각했는데 이부분은 정확하게 모르겠습니다. 3. 동일한 앱에 둘 이상의 React 사본이 있을 수 있습니다 . -> 링크에 나온대로 'npm ls react'를 해보면 사진과 같은 결과가 나옵니다. 혹시 3번이 문제가 있는건가요? 봐도 잘 모르겠습니다...흐ㅠㅠ 커스텀 훅이 아니라 그냥 함수로 만든 후에 재사용해야하나? 싶은데 그 함수는 컴포넌트도 아니고 커스텀훅도 아니라서 useNavigate를 사용할 수 없다는 에러가 떠서 그럼 로그아웃 로직을 사용할 때마다 컴포넌트에서 별도로 navigate처리를 해줘야 할 것 같아서 로그아웃 로직 안에서 useNavigate를 사용해서 커스텀훅으로 만들고 싶습니다...! 이런 형태의 로직은 커스텀훅으로 만들 수 없는건가요? 아니면 제가 뭔가 잘못하고있는게 있을까요ㅜㅠㅠ
개발자
#react
#react-hooks
답변 2
댓글 2
조회 946
2년 전 · 성민 님의 질문 업데이트
리액트 props, state
프론트엔드 개발자를 꿈꾸고 있는 미래지망생 입니다 지금은 국비 학원을 다니면서 html css js를 어느정도 배우고 React를 10일정도 배우면서 props state react-hooks를 배우고 다음주 월요일 부터 개인 프로젝트가 들어가게 되었습니다(학원스케줄) 저는 프로젝트 주제가 마땅히 없어 신한카트 페이지를 만들려고 하고있습니다 근데 막상 하려고 하니 컴포넌트는 나누지만 안에 들어있는 내용은 그냥 쌩 html로 작성한거 같아 전혀 react를 활용 못하고 있는거 같습니다 데이터가 변하지 않는것은props로 데이터가 잘 변하는 것은 state로 지정하라고 들었는대 막상 하니 뭐가 잘 변하는지 잘 안변하는지 이렇게 html 작성하드시 하는게 맞는지 어떻게 하면 좋을까요
개발자
답변 1
댓글 0
추천해요 1
조회 199
3년 전 · 커리어리 Q&A 운영자 님의 새로운 댓글
useId, useTransition을 공식문서에서 봤는데, 사용을 못하나요??
useId, useTransition 를 React공식문서에서 봤는데 저희 프로젝트에서 사용할 수 없네요. 사용할 수 있는 방법이 있을까요? 특히 useTransition은 한번 시도해보고싶어서요. https://reactjs.org/docs/hooks-reference.html#usetransition
개발자
#react
#react-hooks
답변 1
댓글 1
조회 198