Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions src/api/kospi-kosdac/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
export interface StockIndexResponse {
indexName: string;
indexValue: string;
fluctuationRate: string;
}

interface StockData {
kospi: StockIndexResponse | null;
kosdaq: StockIndexResponse | null;
}
import { StockData } from "@/app/main/types";

async function getInitialStockData(): Promise<StockData> {
try {
Expand Down
43 changes: 43 additions & 0 deletions src/app/main/_components/main-contents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { memo } from "react";

import NewsCarousel from "@/app/main/_components/news-carousel";
import SearchStock from "@/app/main/_components/search-stock";
import StockIndexCarousel from "@/app/main/_components/stock-carousel";
import ErrorBoundary from "@/components/common/error-boundary";

import { Fluctuation, News, StockData, TradingVolume } from "../types";
import RankingSection from "./ranking-section";

interface MainContentProps {
initialStockData: StockData;
initialNews: News[];
traddata: TradingVolume[];
flucdata: Fluctuation[];
}

function MainContent({
initialStockData,
initialNews,
traddata,
flucdata,
}: MainContentProps) {
return (
<div className="flex flex-1 flex-col p-10 pt-30 md:px-32 lg:max-w-[calc(100%-320px)]">
<ErrorBoundary errorMessage="검색 기능을 일시적으로 사용할 수 없습니다">
<SearchStock />
</ErrorBoundary>

<ErrorBoundary errorMessage="주가 정보를 불러올 수 없습니다">
<StockIndexCarousel initialData={initialStockData} />
</ErrorBoundary>

<RankingSection traddata={traddata} flucdata={flucdata} />

<ErrorBoundary errorMessage="뉴스를 불러올 수 없습니다">
<NewsCarousel initialData={initialNews} />
</ErrorBoundary>
</div>
);
}
Comment on lines +18 to +41
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

🛠️ Refactor suggestion

성능 최적화 및 에러 처리 검토 결과

검토 결과 다음과 같은 사항들이 확인되었습니다:

  1. RankingSection 컴포넌트만 memo로 최적화되어 있어, SearchStock, StockIndexCarousel, NewsCarousel 컴포넌트들의 메모이제이션이 필요합니다.
  2. ErrorBoundary는 이미 적절한 fallback UI를 구현하고 있어 추가 개선이 필요하지 않습니다. 현재 구현에는 에러 메시지, 설명, 새로고침 버튼이 포함되어 있습니다.

개선이 필요한 부분:

  • SearchStock 컴포넌트에 memo 적용
  • StockIndexCarousel 컴포넌트에 memo 적용
  • NewsCarousel 컴포넌트에 memo 적용
🔗 Analysis chain

컴포넌트 최적화 및 에러 처리 개선 제안

컴포넌트 구현이 전반적으로 잘 되어있지만, 몇 가지 개선사항을 제안드립니다:

  1. 자식 컴포넌트들도 memo로 최적화되어 있는지 확인이 필요합니다.
  2. ErrorBoundary에 fallback UI를 추가하면 좋을 것 같습니다.

자식 컴포넌트들의 메모이제이션 상태를 확인해보겠습니다:

ErrorBoundary 개선 예시:

 <ErrorBoundary errorMessage="검색 기능을 일시적으로 사용할 수 없습니다">
   <SearchStock />
 </ErrorBoundary>

 <ErrorBoundary 
   errorMessage="검색 기능을 일시적으로 사용할 수 없습니다"
+  fallback={
+    <div className="flex items-center justify-center p-4 bg-gray-100 rounded-lg">
+      <p className="text-gray-600">검색 기능을 일시적으로 사용할 수 없습니다</p>
+      <button 
+        onClick={() => window.location.reload()}
+        className="ml-2 px-4 py-2 bg-blue-500 text-white rounded"
+      >
+        다시 시도
+      </button>
+    </div>
+  }
 >
   <SearchStock />
 </ErrorBoundary>

Let me check the ErrorBoundary implementation to complete the verification:


Let me try a different approach to find the ErrorBoundary implementation:


Let me check the complete ErrorBoundary implementation:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 자식 컴포넌트들의 메모이제이션 확인

echo "Checking child components for memo usage..."

# SearchStock 컴포넌트 확인
ast-grep --pattern 'export default memo($_)' src/app/main/_components/search-stock.tsx

# StockIndexCarousel 컴포넌트 확인
ast-grep --pattern 'export default memo($_)' src/app/main/_components/stock-carousel.tsx

# NewsCarousel 컴포넌트 확인
ast-grep --pattern 'export default memo($_)' src/app/main/_components/news-carousel.tsx

# RankingSection 컴포넌트 확인
ast-grep --pattern 'export default memo($_)' src/app/main/_components/ranking-section.tsx

Length of output: 543


Script:

#!/bin/bash
# Check ErrorBoundary implementation
ast-grep --pattern 'class ErrorBoundary extends React.Component {
  $$$
}'

# Also check if there's a functional component implementation
ast-grep --pattern 'function ErrorBoundary($_) {
  $$$
}'

# Check if there's any file containing ErrorBoundary in its name
fd ErrorBoundary

Length of output: 155


Script:

#!/bin/bash
# Search for ErrorBoundary in all files
rg -l "ErrorBoundary"

# Search for ErrorBoundary implementation with context
rg "class.*ErrorBoundary|function.*ErrorBoundary" -A 10

Length of output: 1110


Script:

#!/bin/bash
# Get full ErrorBoundary implementation
cat src/components/common/error-boundary/index.tsx

# Check if there's any existing fallback UI implementation
rg "fallback.*=" src/components/common/error-boundary/index.tsx -A 3

Length of output: 1948


export default memo(MainContent);
22 changes: 22 additions & 0 deletions src/app/main/_components/my-info.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { memo } from "react";

import AssetInfo from "@/app/main/_components/asset-info";
import MyStockInfo from "@/app/main/_components/stock-info";
import ErrorBoundary from "@/components/common/error-boundary";

function Sidebar() {
return (
<div className="w-330 shrink-0">
<div className="sticky top-24 flex flex-col gap-16">
<ErrorBoundary errorMessage="자산 정보를 불러올 수 없습니다">
<AssetInfo />
</ErrorBoundary>
<ErrorBoundary errorMessage="관심 종목을 불러올 수 없습니다">
<MyStockInfo />
</ErrorBoundary>
</div>
</div>
);
}

export default memo(Sidebar);
36 changes: 36 additions & 0 deletions src/app/main/_components/ranking-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use client";

import { memo } from "react";

import FluctuationTable from "@/app/main/_components/flucctuate-table";
import RankingStock from "@/app/main/_components/ranking-stock";
import ErrorBoundary from "@/components/common/error-boundary";

import { Fluctuation, TradingVolume } from "../types";

interface RankingSectionProps {
traddata: TradingVolume[];
flucdata: Fluctuation[];
}

function RankingSection({ traddata, flucdata }: RankingSectionProps) {
return (
<div className="mb-30 flex flex-col gap-20">
<h2 className="mt-80 text-24-700">실시간 랭킹</h2>
<div className="flex w-full gap-30">
<div className="mr-40 w-full">
<ErrorBoundary errorMessage="거래량 순위를 불러올 수 없습니다">
<RankingStock data={traddata} />
</ErrorBoundary>
</div>
<div className="w-full">
<ErrorBoundary errorMessage="변동폭 순위를 불러올 수 없습니다">
<FluctuationTable data={flucdata} />
</ErrorBoundary>
</div>
</div>
</div>
);
}

export default memo(RankingSection);
9 changes: 9 additions & 0 deletions src/app/main/_components/table-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"use client";

import { memo, PropsWithChildren } from "react";

function TableWrapper({ children }: PropsWithChildren) {
return <div className="w-full">{children}</div>;
}

export default memo(TableWrapper);
20 changes: 17 additions & 3 deletions src/app/main/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ export interface StockIndexResponse {
fluctuationRate: string;
}

export interface StockData {
kospi: StockIndexResponse | null;
kosdaq: StockIndexResponse | null;
}

export interface News {
title: string;
link: string;
}

export interface TradingVolume {
stockName: string;
rank: number;
Expand All @@ -13,7 +23,11 @@ export interface TradingVolume {
volumeChangeRate: number;
}

export interface News {
title: string;
link: string;
export interface Fluctuation {
rank: number;
stockName: string;
currentPrice: number;
prevChangePrice: number;
prevSign: string;
prevChangeRate: number;
}
57 changes: 9 additions & 48 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,8 @@ import { QueryClient } from "@tanstack/react-query";
import getInitialStockData from "@/api/kospi-kosdac/index";
import getNews from "@/api/news";
import { getFluctuation, getTradingVolume } from "@/api/ranking-table/index";
import AssetInfo from "@/app/main/_components/asset-info";
import FluctuationTable from "@/app/main/_components/flucctuate-table";
import NewsCarousel from "@/app/main/_components/news-carousel";
import RankingStock from "@/app/main/_components/ranking-stock";
import SearchStock from "@/app/main/_components/search-stock";
import StockIndexCarousel from "@/app/main/_components/stock-carousel";
import MyStockInfo from "@/app/main/_components/stock-info";
import ErrorBoundary from "@/components/common/error-boundary";
import MainContent from "@/app/main/_components/main-contents";
import Sidebar from "@/app/main/_components/my-info";

export default async function Home() {
const queryClient = new QueryClient({
Expand Down Expand Up @@ -43,46 +37,13 @@ export default async function Home() {

return (
<div className="flex xxl:px-230">
{/* 메인 컨텐츠 */}
<div className="flex flex-1 flex-col p-10 pt-30 md:px-32 lg:max-w-[calc(100%-320px)]">
<ErrorBoundary errorMessage="검색 기능을 일시적으로 사용할 수 없습니다">
<SearchStock />
</ErrorBoundary>

<ErrorBoundary errorMessage="주가 정보를 불러올 수 없습니다">
<StockIndexCarousel initialData={initialStockData} />
</ErrorBoundary>

<div className="flex flex-col gap-20">
<h2 className="mt-80 text-24-700">실시간 랭킹</h2>
<div className="flex w-full gap-30">
<div className="mr-50 w-full">
<ErrorBoundary errorMessage="거래량 순위를 불러올 수 없습니다">
<RankingStock data={traddata} />
</ErrorBoundary>
</div>
<div className="w-full">
<ErrorBoundary errorMessage="변동폭 순위를 불러올 수 없습니다">
<FluctuationTable data={flucdata} />
</ErrorBoundary>
</div>
</div>
<ErrorBoundary errorMessage="뉴스를 불러올 수 없습니다">
<NewsCarousel initialData={initialNews} />
</ErrorBoundary>
</div>
</div>
{/* 우측 사이드바 */}
<div className="w-330 shrink-0">
<div className="sticky top-24 flex flex-col gap-16">
<ErrorBoundary errorMessage="자산 정보를 불러올 수 없습니다">
<AssetInfo />
</ErrorBoundary>
<ErrorBoundary errorMessage="관심 종목을 불러올 수 없습니다">
<MyStockInfo />
</ErrorBoundary>
</div>
</div>
<MainContent
initialStockData={initialStockData}
initialNews={initialNews}
traddata={traddata}
flucdata={flucdata}
/>
<Sidebar />
</div>
);
}
Loading