Skip to content

Commit c44b758

Browse files
committed
released 0.1.6
1 parent c1537ee commit c44b758

File tree

5 files changed

+72
-69
lines changed

5 files changed

+72
-69
lines changed

example/src/TileGrid.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,16 @@ export default function TileGrid() {
3232
},
3333
];
3434

35-
const renderItem = (item: any, _: number) => {
35+
const repeatedData = Array(50).fill(data).flat();
36+
37+
const renderItem = (_: any, index: number) => {
3638
return (
3739
<TouchableOpacity
3840
style={{
3941
flex: 1,
4042
}}
4143
onPress={() => {
42-
console.log(item.text, 'pressed');
44+
console.log(index + 1, 'pressed');
4345
}}
4446
>
4547
<View
@@ -58,7 +60,7 @@ export default function TileGrid() {
5860
fontSize: 20,
5961
}}
6062
>
61-
{item.text}
63+
{index + 1}
6264
</Text>
6365
</View>
6466
</TouchableOpacity>
@@ -73,7 +75,7 @@ export default function TileGrid() {
7375
>
7476
<ResponsiveGrid
7577
maxItemsPerColumn={4}
76-
data={data}
78+
data={repeatedData}
7779
itemContainerStyle={{
7880
padding: 2,
7981
}}

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-flexible-grid",
3-
"version": "0.1.5",
3+
"version": "0.1.6",
44
"description": "React Native Flexible Grid is an advanced grid layout system inspired by CSS Grid, designed to facilitate responsive, customizable, and dynamic grid layouts in React Native applications. It supports both responsive and fixed layouts, enabling the creation of intricate designs with minimal effort.",
55
"main": "lib/commonjs/index",
66
"module": "lib/module/index",
@@ -127,4 +127,4 @@
127127
"directories": {
128128
"example": "example"
129129
}
130-
}
130+
}

src/flex-grid/index.tsx

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
66
import type { FlexGridProps, FlexGridTile } from './types';
77
import React, { useEffect, useMemo, useRef, useState } from 'react';
88
import { calcFlexGrid } from './calc-flex-grid';
9+
import useThrottle from '../hooks/use-throttle';
910

1011
export const FlexGrid: React.FC<FlexGridProps> = ({
1112
data = [],
@@ -21,18 +22,13 @@ export const FlexGrid: React.FC<FlexGridProps> = ({
2122
}) => {
2223
const [visibleItems, setVisibleItems] = useState<FlexGridTile[]>([]);
2324

24-
const [containerWidth, setContainerWidth] = useState(0);
25-
const [containerHeight, setContainerHeight] = useState(0);
25+
const [containerSize, setContainerSize] = useState({ width: 0, height: 0 });
2626

2727
const scrollPosition = useRef<{
2828
x: number;
2929
y: number;
3030
}>({ x: 0, y: 0 });
3131

32-
const throttleScrollTimeout = useRef<ReturnType<typeof setTimeout> | null>(
33-
null
34-
);
35-
3632
const { totalHeight, totalWidth, gridItems } = useMemo(() => {
3733
return calcFlexGrid(data, maxColumnRatioUnits, itemSizeUnit);
3834
}, [data, maxColumnRatioUnits, itemSizeUnit]);
@@ -42,14 +38,16 @@ export const FlexGrid: React.FC<FlexGridProps> = ({
4238
const updateVisibleItems = () => {
4339
if (!virtualization) return;
4440

45-
const bufferX = containerWidth * virtualizedBufferFactor;
46-
const bufferY = containerHeight * virtualizedBufferFactor;
41+
const bufferX = containerSize.width * virtualizedBufferFactor;
42+
const bufferY = containerSize.height * virtualizedBufferFactor;
4743

4844
const visibleStartX = Math.max(0, scrollPosition.current.x - bufferX);
49-
const visibleEndX = scrollPosition.current.x + containerWidth + bufferX;
45+
const visibleEndX =
46+
scrollPosition.current.x + containerSize.width + bufferX;
5047

5148
const visibleStartY = Math.max(0, scrollPosition.current.y - bufferY);
52-
const visibleEndY = scrollPosition.current.y + containerHeight + bufferY;
49+
const visibleEndY =
50+
scrollPosition.current.y + containerSize.height + bufferY;
5351

5452
const vItems = gridItems.filter((item) => {
5553
const itemRight = item.left + (item.widthRatio || 1) * itemSizeUnit;
@@ -65,6 +63,11 @@ export const FlexGrid: React.FC<FlexGridProps> = ({
6563
setVisibleItems(vItems);
6664
};
6765

66+
const throttledUpdateVisibleItems = useThrottle(
67+
updateVisibleItems,
68+
scrollEventInterval
69+
);
70+
6871
const onHorizontalScroll = (
6972
event: NativeSyntheticEvent<NativeScrollEvent>
7073
) => {
@@ -77,15 +80,7 @@ export const FlexGrid: React.FC<FlexGridProps> = ({
7780
x: nativeEvent.contentOffset.x,
7881
};
7982

80-
if (throttleScrollTimeout.current !== null) {
81-
return;
82-
}
83-
84-
throttleScrollTimeout.current = setTimeout(() => {
85-
updateVisibleItems();
86-
87-
throttleScrollTimeout.current = null;
88-
}, scrollEventInterval);
83+
throttledUpdateVisibleItems();
8984
};
9085

9186
const onVerticalScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
@@ -98,30 +93,15 @@ export const FlexGrid: React.FC<FlexGridProps> = ({
9893
y: nativeEvent.contentOffset.y,
9994
};
10095

101-
if (throttleScrollTimeout.current !== null) {
102-
return;
103-
}
104-
105-
throttleScrollTimeout.current = setTimeout(() => {
106-
updateVisibleItems();
107-
108-
throttleScrollTimeout.current = null;
109-
}, scrollEventInterval);
96+
throttledUpdateVisibleItems();
11097
};
11198

11299
useEffect(() => {
113100
//recalculate visible items when itemSizeUnit or maxColumnRatioUnits or data changes
114101
if (virtualization) {
115102
updateVisibleItems();
116103
}
117-
}, [
118-
itemSizeUnit,
119-
maxColumnRatioUnits,
120-
data,
121-
virtualization,
122-
containerHeight,
123-
containerWidth,
124-
]);
104+
}, [itemSizeUnit, maxColumnRatioUnits, data, virtualization, containerSize]);
125105

126106
if (!renderedList) {
127107
return null;
@@ -132,8 +112,7 @@ export const FlexGrid: React.FC<FlexGridProps> = ({
132112
style={[{ flexGrow: 1 }, style]}
133113
onLayout={(event) => {
134114
const { width, height } = event.nativeEvent.layout;
135-
setContainerWidth(width);
136-
setContainerHeight(height);
115+
setContainerSize({ width, height });
137116
}}
138117
>
139118
<ScrollView

src/hooks/use-throttle.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { useCallback, useRef } from 'react';
2+
3+
/**
4+
* A hook to throttle function calls.
5+
* @param callback The function to throttle.
6+
* @param delay The throttle delay in milliseconds.
7+
* @returns A throttled version of the provided function.
8+
*/
9+
const useThrottle = <T extends (...args: any[]) => any>(
10+
callback: T,
11+
delay: number
12+
): ((...args: Parameters<T>) => void) => {
13+
const throttleTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
14+
15+
const throttledFunction = useCallback(
16+
(...args: Parameters<T>) => {
17+
if (throttleTimeout.current === null) {
18+
callback(...args);
19+
throttleTimeout.current = setTimeout(() => {
20+
throttleTimeout.current = null;
21+
}, delay);
22+
}
23+
},
24+
25+
[callback, delay]
26+
);
27+
28+
return throttledFunction;
29+
};
30+
31+
export default useThrottle;

src/responsive-grid/index.tsx

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ScrollView, View } from 'react-native';
66
import type { ResponsiveGridProps, TileItem } from './types';
77
import { calcResponsiveGrid } from './calc-responsive-grid';
88
import type { NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
9+
import useThrottle from '../hooks/use-throttle';
910

1011
export const ResponsiveGrid: React.FC<ResponsiveGridProps> = ({
1112
data = [],
@@ -20,12 +21,8 @@ export const ResponsiveGrid: React.FC<ResponsiveGridProps> = ({
2021
itemUnitHeight,
2122
}) => {
2223
const [visibleItems, setVisibleItems] = useState<TileItem[]>([]);
23-
const throttleScrollTimeout = useRef<ReturnType<typeof setTimeout> | null>(
24-
null
25-
);
2624

27-
const [containerWidth, setContainerWidth] = useState(0);
28-
const [containerHeight, setContainerHeight] = useState(0);
25+
const [containerSize, setContainerSize] = useState({ width: 0, height: 0 });
2926

3027
const scrollYPosition = useRef<number>(0);
3128

@@ -34,10 +31,10 @@ export const ResponsiveGrid: React.FC<ResponsiveGridProps> = ({
3431
calcResponsiveGrid(
3532
data,
3633
maxItemsPerColumn,
37-
containerWidth,
34+
containerSize.width,
3835
itemUnitHeight
3936
),
40-
[data, maxItemsPerColumn, containerWidth]
37+
[data, maxItemsPerColumn, containerSize]
4138
);
4239

4340
const renderedItems = virtualization ? visibleItems : gridItems;
@@ -46,11 +43,11 @@ export const ResponsiveGrid: React.FC<ResponsiveGridProps> = ({
4643
if (!virtualization) return;
4744

4845
// Buffer to add outside visible range
49-
const buffer = containerHeight * virtualizedBufferFactor;
46+
const buffer = containerSize.height * virtualizedBufferFactor;
5047

5148
// Define the range of items that are visible based on scroll position
5249
const visibleStart = Math.max(0, scrollYPosition.current - buffer);
53-
const visibleEnd = scrollYPosition.current + containerHeight + buffer;
50+
const visibleEnd = scrollYPosition.current + containerSize.height + buffer;
5451

5552
const vItems = gridItems.filter((item: TileItem) => {
5653
const itemBottom = item.top + item.height;
@@ -63,54 +60,48 @@ export const ResponsiveGrid: React.FC<ResponsiveGridProps> = ({
6360
return vItems;
6461
};
6562

63+
const throttledUpdateVisibleItems = useThrottle(
64+
updateVisibleItems,
65+
scrollEventInterval
66+
);
67+
6668
const onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
67-
// If virtualization is disabled, return
6869
if (!virtualization) return;
6970

7071
const currentScrollY = event.nativeEvent.contentOffset.y;
7172

7273
scrollYPosition.current = currentScrollY;
7374

74-
// Throttling logic
75-
if (throttleScrollTimeout.current !== null) {
76-
return;
77-
}
78-
79-
throttleScrollTimeout.current = setTimeout(() => {
80-
updateVisibleItems();
81-
82-
throttleScrollTimeout.current = null;
83-
}, scrollEventInterval);
75+
throttledUpdateVisibleItems();
8476
};
8577

8678
useEffect(() => {
8779
if (virtualization) {
8880
updateVisibleItems();
8981
}
90-
}, [gridItems, containerHeight, containerWidth, virtualization]);
82+
}, [gridItems, containerSize, virtualization]);
9183

9284
return (
9385
<View
9486
style={[{ flexGrow: 1 }, style]}
9587
onLayout={(event) => {
9688
const { width, height } = event.nativeEvent.layout;
97-
setContainerWidth(width);
98-
setContainerHeight(height);
89+
setContainerSize({ width, height });
9990
}}
10091
>
10192
<ScrollView
10293
onScroll={onScroll}
10394
scrollEventThrottle={32}
10495
contentContainerStyle={{
10596
height: gridViewHeight,
106-
width: containerWidth,
97+
width: containerSize.width,
10798
}}
10899
showsVerticalScrollIndicator={showScrollIndicator}
109100
>
110101
<View
111102
style={{
112103
height: gridViewHeight,
113-
width: containerWidth,
104+
width: containerSize.width,
114105
}}
115106
>
116107
{renderedItems.map((item, index) => (

0 commit comments

Comments
 (0)