1- import { useMemo } from "react" ;
1+ import React , { useCallback , useMemo } from "react" ;
22import dayjs from "dayjs" ;
33import {
44 AddCircleRounded ,
@@ -7,18 +7,18 @@ import {
77 CommitRounded ,
88 RestorePageRounded ,
99 ExpandMoreRounded ,
10- ExpandLessRounded ,
1110} from "@mui/icons-material" ;
1211import { Tooltip } from "@mui/material" ;
12+ import type { ListRowProps } from "react-virtualized" ;
13+ import { List , AutoSizer , CellMeasurer } from "react-virtualized" ;
1314
1415import { useGithubInfo , useDataStore } from "store" ;
1516import { Author } from "components/Common/Author" ;
1617import type { IssueLinkedMessage } from "components/Common/GithubIssueLink" ;
1718import { renderIssueLinkedNodes } from "components/Common/GithubIssueLink" ;
1819
19- import { useCommitListHide } from "./Detail.hook" ;
2020import { getCommitListDetail } from "./Detail.util" ;
21- import { FIRST_SHOW_NUM } from "./Detail.const " ;
21+ import { useVirtualizedList } from "./Detail.hook " ;
2222import type { DetailProps , DetailSummaryProps , DetailSummaryItem , CommitItemProps } from "./Detail.type" ;
2323
2424import "./Detail.scss" ;
@@ -32,14 +32,52 @@ const Detail = ({ clusterId, authSrcMap }: DetailProps) => {
3232 selectedData ?. filter ( ( selected ) => selected . commitNodeList [ 0 ] . clusterId === clusterId ) [ 0 ] . commitNodeList ?? [ ] ,
3333 [ selectedData , clusterId ]
3434 ) ;
35- const { commitNodeList, toggle, handleToggle } = useCommitListHide ( commitNodeListInCluster ) ;
36-
37- const isShow = commitNodeListInCluster . length > FIRST_SHOW_NUM ;
3835
3936 const handleCommitIdCopy = ( id : string ) => async ( ) => {
4037 navigator . clipboard . writeText ( id ) ;
4138 } ;
4239
40+ const { cache, virtualizedItems, showScrollIndicator, handleRowsRendered } =
41+ useVirtualizedList ( commitNodeListInCluster ) ;
42+
43+ const renderCommitItem = useCallback (
44+ ( props : { index : number ; key : string } ) => {
45+ const { index, key } = props ;
46+ const item = virtualizedItems [ index ] ;
47+
48+ if ( item . type === "summary" ) {
49+ return < DetailSummary commitNodeListInCluster = { item . data } /> ;
50+ }
51+ return (
52+ < MemoizedCommitItem
53+ key = { key }
54+ commit = { item . data }
55+ owner = { owner }
56+ repo = { repo }
57+ authSrcMap = { authSrcMap }
58+ handleCommitIdCopy = { handleCommitIdCopy }
59+ linkedMessage = { issueLinkedMessage }
60+ />
61+ ) ;
62+ } ,
63+ [ virtualizedItems ]
64+ ) ;
65+
66+ const rowRenderer = useCallback (
67+ ( { index, key, parent, style } : ListRowProps ) => (
68+ < CellMeasurer
69+ key = { key }
70+ cache = { cache }
71+ parent = { parent }
72+ columnIndex = { 0 }
73+ rowIndex = { index }
74+ >
75+ < div style = { style } > { renderCommitItem ( { index, key } ) } </ div >
76+ </ CellMeasurer >
77+ ) ,
78+ [ cache , renderCommitItem ]
79+ ) ;
80+
4381 const issueLinkedMessage : IssueLinkedMessage = useMemo ( ( ) => {
4482 const message = commitNodeListInCluster ?. [ 0 ] ?. commit ?. message ;
4583 if ( ! message ) return { title : [ ] , body : null } ;
@@ -56,32 +94,30 @@ const Detail = ({ clusterId, authSrcMap }: DetailProps) => {
5694 if ( ! selectedData || selectedData . length === 0 ) return null ;
5795
5896 return (
59- < >
60- < DetailSummary commitNodeListInCluster = { commitNodeListInCluster } />
61- < ul className = "detail__commit-list" >
62- { commitNodeList . map ( ( { commit } ) => (
63- < CommitItem
64- key = { commit . id }
65- commit = { commit }
66- owner = { owner }
67- repo = { repo }
68- authSrcMap = { authSrcMap }
69- handleCommitIdCopy = { handleCommitIdCopy }
70- linkedMessage = { issueLinkedMessage }
71- />
72- ) ) }
73- </ ul >
74-
75- { isShow && (
76- < button
77- type = "button"
78- className = "detail__toggle-button"
79- onClick = { handleToggle }
80- >
81- { toggle ? < ExpandLessRounded /> : < ExpandMoreRounded /> }
82- </ button >
97+ < div className = "detail__container" >
98+ < AutoSizer >
99+ { ( { height, width } ) => {
100+ return (
101+ < List
102+ height = { height }
103+ width = { width }
104+ rowCount = { virtualizedItems . length }
105+ rowHeight = { cache . rowHeight }
106+ rowRenderer = { rowRenderer }
107+ onRowsRendered = { handleRowsRendered }
108+ className = "detail__virtualized-list"
109+ estimatedRowSize = { 120 }
110+ />
111+ ) ;
112+ } }
113+ </ AutoSizer >
114+
115+ { showScrollIndicator && (
116+ < div className = "detail__scroll-indicator" >
117+ < ExpandMoreRounded />
118+ </ div >
83119 ) }
84- </ >
120+ </ div >
85121 ) ;
86122} ;
87123
@@ -90,10 +126,7 @@ export default Detail;
90126function CommitItem ( { commit, owner, repo, authSrcMap, handleCommitIdCopy, linkedMessage } : CommitItemProps ) {
91127 const { id, message, author, commitDate } = commit ;
92128 return (
93- < li
94- key = { id }
95- className = "detail__commit-item"
96- >
129+ < div className = "detail__commit-item" >
97130 < div className = "commit-item__detail" >
98131 < div className = "commit-item__message-container" >
99132 < div className = "commit-message" >
@@ -148,10 +181,12 @@ function CommitItem({ commit, owner, repo, authSrcMap, handleCommitIdCopy, linke
148181 </ div >
149182 </ div >
150183 </ div >
151- </ li >
184+ </ div >
152185 ) ;
153186}
154187
188+ const MemoizedCommitItem = React . memo ( CommitItem ) ;
189+
155190function DetailSummary ( { commitNodeListInCluster } : DetailSummaryProps ) {
156191 const { authorLength, fileLength, commitLength, insertions, deletions } = getCommitListDetail ( {
157192 commitNodeListInCluster,
0 commit comments