Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

4 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ’ป Spaghetti Code Refactor

๐Ÿ“Œ router ๋ถ„๋ฆฌ

router/router.jsx

import { createBrowserRouter } from "react-router-dom";
import HomePage from "../pages/Home";
import PostListPage from "../pages/Post.List";
import PostDetailPage from "../pages/Post.detail";

export const router = createBrowserRouter([
 { path: "/", element: <HomePage /> },
 { path: "/posts", element: <PostListPage /> },
 { path: "/post-detail/:postId", element: <PostDetailPage /> },
]);

๐Ÿ’ก๋ฆฌํŒฉํ† ๋ง ๋‚ด์šฉ

  • App.jsx์—์„œ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ๋˜ router ๋กœ์ง์„ ๋ถ„๋ฆฌํ•˜์—ฌ App.jsx์—์„œ importํ•ด์„œ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ ์žฌ์‚ฌ์šฉ๋˜๋Š” ๊ฐ’์€ consts๋กœ

consts/pageNation.jsx

export const LIMIT_TAKE = 10;
export const LIMIT_PAGE = 10;

consts/queryKey.jsx

export const QUERY_KEY = {
 post: "post",
 posts: "posts",
 comments: "comments",
 weather: "weather",
};

๐Ÿ’ก๋ฆฌํŒฉํ† ๋ง ๋‚ด์šฉ

  • LIMIT_PAGE, LIMIT_TAKE ๊ฐ’์€ pageNation์—์„œ ์ž์ฃผ ์žฌ์‚ฌ์šฉ๋˜๋Š” ๊ฐ’์ด๋ฏ€๋กœ consts ํด๋”๋กœ ๊ด€๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.
  • react-query๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ msw ๋ฐ์ดํ„ฐ๋ฅผ ํ˜ธ์ถœํ• ๋•Œ ์‚ฌ์šฉ๋˜๋Š” query-key๊ฐ’ ๋˜ํ•œ ์ž์ฃผ ์žฌ์‚ฌ์šฉ๋˜๋ฏ€๋กœ consts ํด๋”๋กœ ๊ด€๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ msw ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ

apis/api.jsx

import axios from "axios";
import { weatherConfig } from "../third-party/weather.config";
import { LIMIT_PAGE, LIMIT_TAKE } from "../consts/pageNation";

export const getPostDetailPost = async () => {
 const response = await axios.get("/api/post");
 return response.data;
};

export const getPaginationPost = async (params) => {
 const response = await axios.get("/api/posts", {
   params: {
     page: params.get("page") ?? 1,
     take: params.get("take") ?? LIMIT_TAKE,
     limit: params.get("limit") ?? LIMIT_PAGE,
   },
 });
 return response.data;
};

export const getPaginationComment = async (params) => {
 const response = await axios.get("/api/comments", {
   params: {
     page: params.get("page") ?? 1,
     take: params.get("take") ?? LIMIT_TAKE,
     limit: params.get("limit") ?? LIMIT_PAGE,
   },
 });
 return response.data;
};

export const getWeather = async () => {
 try {
   const response = await axios.get("/getUltraSrtNcst", {
     baseURL: weatherConfig.api,
     params: {
       serviceKey: weatherConfig.secret_key,
       dataType: "JSON",
       base_date: new Date().toISOString().substring(0, 10).replace(/-/g, ""),
       base_time: "0600",
       nx: 60,
       ny: 127,
     },
   });
   return response.data;
 } catch (err) {
   console.log(err);
   throw new Error("failed load weather api");
 }
};

components/pagenation/Pagenation.Comment.jsx

 const { data: commentData } = useQuery([QUERY_KEY.comments, params.get("page")], () => getPaginationComment(params));
 const paginationData = commentData?.PageNation;

components/pagenation/Pagenation.Post.jsx

 const { data: postData } = useQuery([QUERY_KEY.posts, params.get("page")], () => getPaginationPost(params));
 const pageNationData = postData?.PageNation;

pages/Home.jsx

 const { data: weatherData } = useQuery([QUERY_KEY.weather], () => getWeather());

pages/Post.Detail.jsx

 const { data: postDetailData } = useQuery([QUERY_KEY.post], () => getPostDetailPost());
 const { data: commentData } = useQuery([QUERY_KEY.comments, params.get("page")], () => getPaginationComment(params));
 const paginationCommentData = commentData?.Comments;

pages/Post.List.jsx

 const { data: postData } = useQuery([QUERY_KEY.posts, params.get("page")], () => getPaginationPost(params));
 const paginationPostData = postData?.Posts;

๐Ÿ’ก๋ฆฌํŒฉํ† ๋ง ๋‚ด์šฉ

  • api์™€ ๊ด€๋ จ๋œ ๋กœ์ง์€ apiํด๋”์—์„œ ๊ด€๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.
  • api ํ˜ธ์ถœ ํ•จ์ˆ˜(Post ๋กœ์ง)์— params ๊ฐ’์„ ์ „๋‹ฌํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด {PageNation:,Posts:} ํ˜•์‹์œผ๋กœ ๋‚˜์˜ค๋Š”๋ฐ ์ด๋•Œ PageNation ๊ฐ’์€ pagenation ํด๋”์—์„œ Posts ๊ฐ’์€ pages ํด๋”์—์„œ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
  • api ํ˜ธ์ถœ ํ•จ์ˆ˜(Comment ๋กœ์ง)์— params ๊ฐ’์„ ์ „๋‹ฌํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด {PageNation:,Comments:} ํ˜•์‹์œผ๋กœ ๋‚˜์˜ค๋Š”๋ฐ ์ด๋•Œ PageNation ๊ฐ’์€ pagenation ํด๋”์—์„œ Comments ๊ฐ’์€ pages ํด๋”์—์„œ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ state๋ฅผ ์ด์šฉํ•œ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋กœ์ง์€ hooks๋กœ

hooks/useDiaLog.jsx

import { DialLogState, useDiaLogStore } from "../contexts/DialogProvider";

const useDiaLog = () => {
 const [, setDiaLogAttribute] = useDiaLogStore();

 // home page
 const onPressNavigateBlog = () => {
   setDiaLogAttribute({
     type: DialLogState.ALERT,
     text: "์ •๋ง๋กœ ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๊ฒ ์Šต๋‹ˆ๊นŒ",
     isOpen: true,
     onConfirm: async () => {
       await setDiaLogAttribute({ isOpen: false });
       window.location.href = "/posts";
     },
   });
 };

 // postList page
 const onClickPost = async (postId) => {
   await setDiaLogAttribute({
     type: DialLogState.CONFIRM,
     text: "์ •๋ง๋กœ ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๊ฒ ์Šต๋‹ˆ๊นŒ",
     isOpen: true,
     onConfirm: async () => {
       await setDiaLogAttribute({
         text: "์ •๋ง๋กœ ์ด๋™ํ•ด๋ฒ„๋ฆฐ๋‹ค์š”!",
         onConfirm: async () => {
           window.location.href = `/post-detail/${postId}`;
         },
       });
     },
     onCancel: () => {
       setDiaLogAttribute({ isOpen: false });
     },
   });
 };
 return { onPressNavigateBlog, onClickPost };
};

export default useDiaLog;

hooks/useShowModal.jsx

import { useState } from "react";

const useShowModal = () => {
 const [isOpenCommentList, setIsOpenCommentList] = useState(false);

 const onClickMoreComments = async () => {
   setIsOpenCommentList(true);
 };

 const onClickHiddenComments = () => {
   setIsOpenCommentList(false);
 };

 return { isOpenCommentList, onClickMoreComments, onClickHiddenComments };
};

export default useShowModal;

๐Ÿ’ก๋ฆฌํŒฉํ† ๋ง ๋‚ด์šฉ

  • context๋ฅผ ํ†ตํ•ด dialog์™€ ๊ด€๋ จ๋œ ์ƒํƒœ๋ฅผ ์ „์—ญ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ์ง€๋งŒ ์ด ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋Š” ์—ฌ๋Ÿฌ ํŒŒ์ผ์—์„œ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ „์—ญ์ ์œผ๋กœ ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ๋Š” dialog์™€ ๊ด€๋ จ๋œ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ useDiaLog custom hook์œผ๋กœ ๋งŒ๋“ค์–ด ํ•„์š”ํ• ๋•Œ import ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๋Œ“๊ธ€์ฐฝ์„ ์—ด๊ณ  ๋‹ซ์„ ์ˆ˜ ์žˆ๋Š” ๋กœ์ง์ธ useShowModal์€ ํ•ด๋‹น ์ฝ”๋“œ์—์„œ๋Š” ์žฌ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์ง€ ์•Š์ง€๋งŒ ๋‹จ์ˆœํžˆ ๋ชจ๋‹ฌ์ฐฝ์„ ์—ด๊ณ  ๋‹ซ๋Š” ๋กœ์ง์€ ์ž์ฃผ ์žฌ์‚ฌ์šฉ๋ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์—ฌ custom hook์œผ๋กœ ๋ถ„๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ localStorage์™€ ๊ด€๋ จ๋œ ๋กœ์ง์€ ๋ฌถ์–ด์„œ

repository/userNameRepository.jsx

const USER_NAME = "useName";

export const userNameRepository = {
 getUserName() {
   return localStorage.getItem(USER_NAME);
 },

 setUserName(userName) {
   localStorage.setItem(USER_NAME, userName);
 },
};

๐Ÿ’ก๋ฆฌํŒฉํ† ๋ง ๋‚ด์šฉ

  • localStorage๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋Š” ๋กœ์ง์ด๋‚˜ localStorage์— ์žˆ๋Š” ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋กœ์ง์€ ์ž์ฃผ ์žฌ์‚ฌ์šฉ๋˜๋ฏ€๋กœ repository ํด๋”์—์„œ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๊ด€๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ private router์— ๊ด€๋ จ๋œ ๋กœ์ง์€ util ํ•จ์ˆ˜๋กœ ๊ด€๋ฆฌ

utils/privateRouter.jsx

import { userNameRepository } from "../repository/userNameRepository";

const privateRouter = () => {
 const userName = userNameRepository.getUserName();
 if (!userName) {
   alert("๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค");
   window.location.href = "/";
 }
};

export default privateRouter;

๐Ÿ’ก๋ฆฌํŒฉํ† ๋ง ๋‚ด์šฉ

  • localStorage์— ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์„๋•Œ ํ™ˆํŽ˜์ด์ง€๋กœ ๋˜๋Œ์•„๊ฐ€๋Š” private Router์™€ ๊ด€๋ จ๋œ ํ•จ์ˆ˜๋Š” ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๊ฐ€ ์•„๋‹Œ ๋ชจ๋“  ํŽ˜์ด์ง€์—์„œ ์žฌ์‚ฌ์šฉ๋˜์ง€๋งŒ state๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— utils ํด๋”์—์„œ ๊ด€๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ style์€ ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌ

pages/style.jsx

import styled from "styled-components";

const BlurBackGround = styled.div`
 position: fixed;
 width: 100%;
 height: 100vh;
 z-index: 9999;
 backdrop-filter: blur(10px);
`;

const UserNameForm = styled.form`
 display: flex;
 flex-direction: column;
 align-items: center;
 justify-content: center;
 height: 100%;
`;

const Button = styled.button``;

export const S = {
 BlurBackGround,
 UserNameForm,
 Button,
};

๐Ÿ’ก๋ฆฌํŒฉํ† ๋ง ๋‚ด์šฉ

  • style ๊ด€๋ จ ๋กœ์ง์„ page์—์„œ componets์—์„œ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์ง€๊ณ  ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๋ฏ€๋กœ style ํด๋”๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ด€๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages