@@ -12,13 +12,13 @@ export default function Community() {
1212 const [ posts , setPosts ] = useState ( [ ] ) ;
1313 const [ loading , setLoading ] = useState ( true ) ;
1414 const [ error , setError ] = useState ( "" ) ;
15-
1615 const [ searchInput , setSearchInput ] = useState ( "" ) ;
1716 const [ tagInput , setTagInput ] = useState ( "" ) ;
1817 const [ keyword , setKeyword ] = useState ( "" ) ;
1918 const [ tagKeyword , setTagKeyword ] = useState ( [ ] ) ;
2019 const [ currentPage , setCurrentPage ] = useState ( 1 ) ;
21- const ITEMS_PER_PAGE = 10 ;
20+
21+ const PAGE_SIZE = 10 ;
2222
2323 useEffect ( ( ) => {
2424 let ignore = false ;
@@ -101,7 +101,7 @@ export default function Community() {
101101 return posts ;
102102 }
103103
104- const lowerKeyword = keyword . toLowerCase ( ) ;
104+ const lowerKeyword = keyword . toLowerCase ( ) ;
105105
106106 return posts . filter ( ( post ) => {
107107 const matchesKeyword = lowerKeyword
@@ -121,18 +121,6 @@ export default function Community() {
121121 } ) ;
122122 } , [ keyword , tagKeyword , posts ] ) ;
123123
124- useEffect ( ( ) => {
125- setCurrentPage ( 1 ) ;
126- } , [ keyword , tagKeyword ] ) ;
127-
128- useEffect ( ( ) => {
129- const lastPage = Math . max ( 1 , Math . ceil ( filteredPosts . length / ITEMS_PER_PAGE ) ) ;
130- setCurrentPage ( ( prev ) => {
131- const next = Math . min ( prev , lastPage ) ;
132- return next === prev ? prev : next ;
133- } ) ;
134- } , [ filteredPosts . length , ITEMS_PER_PAGE ] ) ;
135-
136124 const handleSearchSubmit = ( event ) => {
137125 event ?. preventDefault ?. ( ) ;
138126 const trimmedKeyword = searchInput . trim ( ) ;
@@ -154,31 +142,43 @@ export default function Community() {
154142 setCurrentPage ( 1 ) ;
155143 } ;
156144
157- const totalPages = Math . max ( 1 , Math . ceil ( filteredPosts . length / ITEMS_PER_PAGE ) ) ;
158- const hasResults = filteredPosts . length > 0 ;
159- const startIndex = ( currentPage - 1 ) * ITEMS_PER_PAGE ;
160- const visiblePosts = useMemo (
161- ( ) => ( hasResults ? filteredPosts . slice ( startIndex , startIndex + ITEMS_PER_PAGE ) : [ ] ) ,
162- [ filteredPosts , hasResults , startIndex , ITEMS_PER_PAGE ]
163- ) ;
145+ const totalPages = useMemo ( ( ) => {
146+ const count = Math . ceil ( filteredPosts . length / PAGE_SIZE ) ;
147+ return count > 0 ? count : 1 ;
148+ } , [ filteredPosts . length ] ) ;
149+
150+ useEffect ( ( ) => {
151+ if ( currentPage > totalPages ) {
152+ setCurrentPage ( totalPages ) ;
153+ }
154+ } , [ currentPage , totalPages ] ) ;
155+
156+ const pageNumbers = useMemo ( ( ) => (
157+ Array . from ( { length : totalPages } , ( _ , index ) => index + 1 )
158+ ) , [ totalPages ] ) ;
159+
160+ const paginatedPosts = useMemo ( ( ) => {
161+ const start = ( currentPage - 1 ) * PAGE_SIZE ;
162+ const end = start + PAGE_SIZE ;
163+ return filteredPosts . slice ( start , end ) ;
164+ } , [ filteredPosts , currentPage ] ) ;
164165
166+ const jumpBy = 5 ;
165167 const goToPage = ( page ) => {
166- const next = Math . min ( Math . max ( page , 1 ) , Math . max ( 1 , totalPages ) ) ;
167- setCurrentPage ( next ) ;
168+ if ( page < 1 || page > totalPages ) return ;
169+ setCurrentPage ( page ) ;
168170 } ;
169171
170- const goToFirst = ( ) => goToPage ( 1 ) ;
171- const goToLast = ( ) => goToPage ( totalPages ) ;
172- const goToPreviousGroup = ( ) => goToPage ( currentPage - 5 ) ;
173- const goToNextGroup = ( ) => goToPage ( currentPage + 5 ) ;
174-
175- const pageNumbers = useMemo ( ( ) => {
176- const numbers = [ ] ;
177- for ( let i = 1 ; i <= totalPages ; i += 1 ) {
178- numbers . push ( i ) ;
172+ const handleChunkMove = ( direction ) => {
173+ const target = currentPage + direction * jumpBy ;
174+ if ( target < 1 ) {
175+ setCurrentPage ( 1 ) ;
176+ } else if ( target > totalPages ) {
177+ setCurrentPage ( totalPages ) ;
178+ } else {
179+ setCurrentPage ( target ) ;
179180 }
180- return numbers ;
181- } , [ totalPages ] ) ;
181+ } ;
182182
183183 return (
184184 < div className = "community-wrapper" >
@@ -266,7 +266,7 @@ export default function Community() {
266266
267267 { ! loading && ! error && filteredPosts . length > 0 && (
268268 < div className = "post-list" >
269- { filteredPosts . map ( ( post ) => (
269+ { paginatedPosts . map ( ( post ) => (
270270 < div
271271 key = { post . id }
272272 className = "post-card"
@@ -304,16 +304,54 @@ export default function Community() {
304304 </ div >
305305 ) }
306306
307- < div className = "pagination-wrapper" >
308- < div className = "page-numbers" >
309- < button className = "page-button active" > 1</ button >
310- < button className = "page-button" > 2</ button >
311- < button className = "page-button" > 3</ button >
312- < button className = "page-button" > 4</ button >
313- < button className = "page-button" > 5</ button >
307+ { filteredPosts . length > 0 && (
308+ < div className = "pagination-wrapper" >
309+ < div className = "page-numbers" >
310+ < button
311+ type = "button"
312+ className = "page-button"
313+ onClick = { ( ) => goToPage ( 1 ) }
314+ disabled = { currentPage === 1 }
315+ >
316+ 처음
317+ </ button >
318+ < button
319+ type = "button"
320+ className = "page-button"
321+ onClick = { ( ) => handleChunkMove ( - 1 ) }
322+ disabled = { currentPage === 1 }
323+ >
324+ -5쪽
325+ </ button >
326+ { pageNumbers . map ( ( page ) => (
327+ < button
328+ key = { page }
329+ type = "button"
330+ className = { `page-button${ page === currentPage ? " active" : "" } ` }
331+ onClick = { ( ) => goToPage ( page ) }
332+ >
333+ { page }
334+ </ button >
335+ ) ) }
336+ < button
337+ type = "button"
338+ className = "page-button"
339+ onClick = { ( ) => handleChunkMove ( 1 ) }
340+ disabled = { currentPage === totalPages }
341+ >
342+ +5쪽
343+ </ button >
344+ < button
345+ type = "button"
346+ className = "page-button"
347+ onClick = { ( ) => goToPage ( totalPages ) }
348+ disabled = { currentPage === totalPages }
349+ >
350+ 마지막
351+ </ button >
352+ </ div >
314353 </ div >
315- < button className = "next-page" > 다음 페이지</ button >
316- </ div >
354+ ) }
317355 </ main >
318356
319357 < aside className = "sidebar-right" >
0 commit comments