@@ -12,6 +12,7 @@ const state = {
1212 products : [ ] ,
1313 pagination : { } ,
1414 categories : { } ,
15+ watchRegistered : false ,
1516} ;
1617
1718const fetchProducts = async ( params = { } ) => {
@@ -23,14 +24,17 @@ const fetchProducts = async (params = {}) => {
2324 }
2425
2526 const productData = await getProducts ( params ) ;
26- state . isLoading = false ;
2727
2828 // 무한 스크롤 방식 구현으로 누적된 product 값
2929 if ( params . page && params . page > 1 ) {
3030 state . products = [ ...state . products , ...productData . products ] ;
31- state . isLoadingMore = false ;
31+ // 로딩을 조금 늦게 false로 설정
32+ setTimeout ( ( ) => {
33+ state . isLoadingMore = false ;
34+ } , 500 ) ;
3235 } else {
3336 state . products = productData . products ;
37+ state . isLoading = false ;
3438 }
3539
3640 state . pagination = productData . pagination ;
@@ -42,32 +46,48 @@ const fetchCategories = async () => {
4246 state . isLoading = false ;
4347} ;
4448
49+ let scrollHandler = null ;
50+ let scrollTimeout = null ;
51+
4552const fetchMoreProductsScroll = ( ) => {
4653 const location = getAppPath ( ) ;
4754 if ( location !== "/" ) return ;
4855 const triggerHeight = 100 ;
49- let scrollHandler = null ;
5056
5157 const handleScroll = ( ) => {
5258 const location = getAppPath ( ) ;
5359 // 메인페이지에서만 가능하도록 처리
5460 if ( location !== "/" ) return ;
55- if ( state . isLoadingMore || ! state . pagination ?. hasNext ) return ;
61+ // 로딩 중이거나 다음 페이지가 없으면 스크롤 감지 안함
62+ if ( state . isLoadingMore || state . isLoading || ! state . pagination ?. hasNext ) return ;
63+
5664 const currentScroll = window . scrollY ;
5765 const viewHeight = document . documentElement . clientHeight ;
5866 const bodyHeight = document . body . scrollHeight ;
67+
5968 if ( currentScroll + viewHeight > bodyHeight - triggerHeight ) {
60- state . isLoadingMore = true ;
61- const currentPage = store . get ( "params" ) [ "page" ] ;
62- store . set ( "params" , {
63- ...store . get ( "params" ) ,
64- page : currentPage + 1 ,
65- } ) ;
69+ if ( state . isLoadingMore ) return ;
70+
71+ if ( scrollTimeout ) {
72+ clearTimeout ( scrollTimeout ) ;
73+ }
74+
75+ scrollTimeout = setTimeout ( ( ) => {
76+ if ( state . isLoadingMore || state . isLoading ) return ;
77+
78+ state . isLoadingMore = true ;
79+ const currentPage = store . get ( "params" ) [ "page" ] || 1 ;
80+ store . set ( "params" , {
81+ ...store . get ( "params" ) ,
82+ page : currentPage + 1 ,
83+ } ) ;
84+ } , 300 ) ;
6685 }
6786 } ;
6887
88+ // 기존 스크롤 핸들러 제거
6989 if ( scrollHandler ) {
70- window . removeEventListener ( "scroll" , handleScroll ) ;
90+ window . removeEventListener ( "scroll" , scrollHandler ) ;
7191 }
7292
7393 scrollHandler = handleScroll ;
@@ -91,6 +111,7 @@ const renderHome = () => {
91111
92112Home . init = ( ) => {
93113 state . isLoading = true ;
114+ state . watchRegistered = false ;
94115} ;
95116
96117Home . mount = async ( ) => {
@@ -112,38 +133,74 @@ Home.mount = async () => {
112133
113134 fetchMoreProductsScroll ( ) ;
114135
115- store . watch ( async ( newValue ) => {
116- const url = new URL ( window . location ) ;
117- Object . entries ( newValue ) . forEach ( ( [ key , value ] ) => {
118- if ( value !== "" && value ) {
119- url . searchParams . set ( key , value ) ;
120- } else {
121- url . searchParams . delete ( key ) ;
136+ // store.watch 중복 등록 방지
137+ if ( ! state . watchRegistered ) {
138+ state . watchRegistered = true ;
139+ store . watch ( async ( newValue ) => {
140+ console . log ( "test" ) ;
141+ // 무한 스크롤로 인한 page 변경은 별도 처리
142+ if ( state . isLoadingMore && newValue . page ) {
143+ await fetchProducts ( newValue ) ;
144+ state . isLoadingMore = false ;
145+
146+ render . draw (
147+ "#product-list" ,
148+ ProductList ( {
149+ products : state . products ,
150+ pagination : state . pagination ,
151+ } ) ,
152+ ) ;
153+ ProductList . mount ( state . products ) ;
154+ ProductCard . mount ( ) ;
155+ return ;
122156 }
123- } ) ;
124- window . history . pushState ( { } , "" , url . toString ( ) ) ;
125157
126- await fetchProducts ( newValue ) ;
127- state . isLoadingMore = false ;
158+ const url = new URL ( window . location ) ;
159+ Object . entries ( newValue ) . forEach ( ( [ key , value ] ) => {
160+ if ( value !== "" && value ) {
161+ url . searchParams . set ( key , value ) ;
162+ } else {
163+ url . searchParams . delete ( key ) ;
164+ }
165+ } ) ;
166+ window . history . pushState ( { } , "" , url . toString ( ) ) ;
167+
168+ await fetchProducts ( newValue ) ;
169+ state . isLoadingMore = false ;
170+
171+ render . draw ( "#search-container" , Search ( store . get ( "categories" ) , false ) ) ;
172+ Search . mount ( ) ;
128173
129- render . draw ( "#search -container" , Search ( store . get ( "categories" ) , false ) ) ;
130- Search . mount ( ) ;
174+ render . draw ( "#breadcrumb -container" , Breadcrumb ( ) ) ;
175+ Breadcrumb . mount ( ) ;
131176
132- render . draw ( "#breadcrumb-container" , Breadcrumb ( ) ) ;
133- Breadcrumb . mount ( ) ;
177+ render . draw (
178+ "#product-list" ,
179+ ProductList ( {
180+ products : state . products ,
181+ pagination : state . pagination ,
182+ } ) ,
183+ ) ;
134184
135- render . draw (
136- "#product-list" ,
137- ProductList ( {
138- products : state . products ,
139- pagination : state . pagination ,
140- } ) ,
141- ) ;
185+ ProductList . mount ( state . products ) ;
142186
143- ProductList . mount ( state . products ) ;
187+ ProductCard . mount ( ) ;
188+ } , "params" ) ;
189+ }
190+ } ;
144191
145- ProductCard . mount ( ) ;
146- } , "params" ) ;
192+ Home . unmount = ( ) => {
193+ // 스크롤 이벤트 리스너 정리
194+ if ( scrollHandler ) {
195+ window . removeEventListener ( "scroll" , scrollHandler ) ;
196+ scrollHandler = null ;
197+ }
198+
199+ // 타이머 정리
200+ if ( scrollTimeout ) {
201+ clearTimeout ( scrollTimeout ) ;
202+ scrollTimeout = null ;
203+ }
147204} ;
148205
149206export default function Home ( { products, pagination, isLoading, categories, isLoadingMore } ) {
0 commit comments