oihana-next-ui 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/@configs/index.js +1 -1
- package/src/@configs/navigation.js +1 -1
- package/src/@configs/ui/splashScreen.js +1 -1
- package/src/@locale/index.js +2 -2
- package/src/components/layouts/InfiniteScroll.jsx +3 -3
- package/src/demo/layouts/InfiniteScrollDemo.jsx +17 -5
- package/src/display/Application.jsx +5 -5
- package/src/hooks/useInfiniteScroll.js +7 -1
- package/src/version.js +1 -1
package/package.json
CHANGED
package/src/@configs/index.js
CHANGED
package/src/@locale/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import getLocaleFromI18n from '
|
|
1
|
+
import getLocaleFromI18n from '../contexts/locale/helpers/getLocaleFromI18n' ;
|
|
2
2
|
|
|
3
3
|
import 'dayjs/locale/fr' ;
|
|
4
4
|
import 'dayjs/locale/en' ;
|
|
5
5
|
|
|
6
|
-
import languages from '
|
|
6
|
+
import languages from '../@configs/languages' ;
|
|
7
7
|
|
|
8
8
|
import app from './app' ;
|
|
9
9
|
import components from './components' ;
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { useRef } from 'react' ;
|
|
4
4
|
|
|
5
|
-
import Loading from '
|
|
5
|
+
import Loading from '../Loading' ;
|
|
6
6
|
|
|
7
|
-
import useInfiniteScroll from '
|
|
7
|
+
import useInfiniteScroll from '../../hooks/useInfiniteScroll' ;
|
|
8
8
|
|
|
9
|
-
import cn from '
|
|
9
|
+
import cn from '../../themes/helpers/cn' ;
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Default root element type for the InfiniteScroll container.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client' ;
|
|
2
2
|
|
|
3
|
-
import { useCallback , useEffect , useState } from 'react' ;
|
|
3
|
+
import { useCallback , useEffect , useRef , useState } from 'react' ;
|
|
4
4
|
|
|
5
5
|
import InfiniteScroll from '@/components/layouts/InfiniteScroll' ;
|
|
6
6
|
import List from '@/components/lists/List' ;
|
|
@@ -192,15 +192,20 @@ const ChatPanel = () =>
|
|
|
192
192
|
const [ loading , setLoading ] = useState( false ) ;
|
|
193
193
|
const [ hasMore , setHasMore ] = useState( true ) ;
|
|
194
194
|
|
|
195
|
+
// Synchronous re-entrancy guard : blocks double loads from React StrictMode's
|
|
196
|
+
// double-invoke and from IntersectionObserver bursts, before any await.
|
|
197
|
+
const loadingRef = useRef( false ) ;
|
|
198
|
+
|
|
195
199
|
// --------- Prepend the previous (older) page of messages
|
|
196
200
|
|
|
197
201
|
const loadOlder = useCallback( async () =>
|
|
198
202
|
{
|
|
199
|
-
if (
|
|
203
|
+
if ( loadingRef.current || !hasMore )
|
|
200
204
|
{
|
|
201
205
|
return ;
|
|
202
206
|
}
|
|
203
207
|
|
|
208
|
+
loadingRef.current = true ;
|
|
204
209
|
setLoading( true ) ;
|
|
205
210
|
|
|
206
211
|
await new Promise( resolve => setTimeout( resolve , LATENCY ) ) ;
|
|
@@ -212,8 +217,9 @@ const ChatPanel = () =>
|
|
|
212
217
|
setLoaded( prev => [ ...older , ...prev ] ) ;
|
|
213
218
|
setHasMore( start > 0 ) ;
|
|
214
219
|
setLoading( false ) ;
|
|
220
|
+
loadingRef.current = false ;
|
|
215
221
|
}
|
|
216
|
-
, [ hasMore , loaded.length
|
|
222
|
+
, [ hasMore , loaded.length ] ) ;
|
|
217
223
|
|
|
218
224
|
// --------- Initial load (most recent page)
|
|
219
225
|
|
|
@@ -255,15 +261,20 @@ const InfiniteScrollDemo = () =>
|
|
|
255
261
|
const [ loading , setLoading ] = useState( false ) ;
|
|
256
262
|
const [ hasMore , setHasMore ] = useState( true ) ;
|
|
257
263
|
|
|
264
|
+
// Synchronous re-entrancy guard : blocks double loads from React StrictMode's
|
|
265
|
+
// double-invoke and from IntersectionObserver bursts, before any await.
|
|
266
|
+
const loadingRef = useRef( false ) ;
|
|
267
|
+
|
|
258
268
|
// --------- Append the next page, guarding against concurrent loads
|
|
259
269
|
|
|
260
270
|
const loadMore = useCallback( async () =>
|
|
261
271
|
{
|
|
262
|
-
if (
|
|
272
|
+
if ( loadingRef.current || !hasMore )
|
|
263
273
|
{
|
|
264
274
|
return ;
|
|
265
275
|
}
|
|
266
276
|
|
|
277
|
+
loadingRef.current = true ;
|
|
267
278
|
setLoading( true ) ;
|
|
268
279
|
|
|
269
280
|
const { items : newItems , hasMore : more } = await fetchPage( page ) ;
|
|
@@ -272,8 +283,9 @@ const InfiniteScrollDemo = () =>
|
|
|
272
283
|
setHasMore( more ) ;
|
|
273
284
|
setPage( prev => prev + 1 ) ;
|
|
274
285
|
setLoading( false ) ;
|
|
286
|
+
loadingRef.current = false ;
|
|
275
287
|
}
|
|
276
|
-
, [ hasMore ,
|
|
288
|
+
, [ hasMore , page ] ) ;
|
|
277
289
|
|
|
278
290
|
// --------- Initial load
|
|
279
291
|
|
|
@@ -21,11 +21,11 @@ import SplashScreen from './SplashScreen';
|
|
|
21
21
|
|
|
22
22
|
import useVersionCheck from '../hooks/useVersionCheck'
|
|
23
23
|
|
|
24
|
-
import config from '
|
|
25
|
-
import languages from '
|
|
26
|
-
import locale from '
|
|
27
|
-
import navigation from '
|
|
28
|
-
import splashScreen from '
|
|
24
|
+
import config from '../@configs'
|
|
25
|
+
import languages from '../@configs/languages'
|
|
26
|
+
import locale from '../@locale'
|
|
27
|
+
import navigation from '../@configs/navigation'
|
|
28
|
+
import splashScreen from '../@configs/ui/splashScreen' ;
|
|
29
29
|
|
|
30
30
|
const { defaultLang , version , versionCheck } = config ;
|
|
31
31
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect , useRef } from 'react' ;
|
|
4
4
|
|
|
5
|
-
import resolveRefElement from '
|
|
5
|
+
import resolveRefElement from '../helpers/react/resolveRefElement' ;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Default distance, before the sentinel is reached, at which loading is triggered.
|
|
@@ -28,6 +28,12 @@ export const DEFAULT_THRESHOLD = 0 ;
|
|
|
28
28
|
* Note : `onLoadMore` should be stable (wrap it in `useCallback`), otherwise
|
|
29
29
|
* the observer is recreated on every render.
|
|
30
30
|
*
|
|
31
|
+
* Note : `onLoadMore` should also be re-entrancy safe. Because the `loading`
|
|
32
|
+
* state is asynchronous, React StrictMode's double-invoke and observer bursts
|
|
33
|
+
* can call it again before `loading` flips — guard with a synchronous ref
|
|
34
|
+
* (`if ( loadingRef.current ) return ; loadingRef.current = true ;`) to avoid
|
|
35
|
+
* loading the same page twice (which yields duplicate React keys).
|
|
36
|
+
*
|
|
31
37
|
* @param {Object} [options]
|
|
32
38
|
* @param {boolean} [options.hasMore=true] - Whether more items can be loaded.
|
|
33
39
|
* @param {boolean} [options.loading=false] - Pauses observation while a load is in flight.
|
package/src/version.js
CHANGED