Skip to content

Commit 231c3fb

Browse files
author
Marek Fořt
committed
CellRendererComponent prop
1 parent fd1a264 commit 231c3fb

File tree

7 files changed

+62
-10
lines changed

7 files changed

+62
-10
lines changed

android/src/main/kotlin/com/shopify/reactnative/flash_list/AutoLayoutView.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,14 @@ class AutoLayoutView(context: Context) : ReactViewGroup(context) {
5151
* Performance: Sort is needed. Given relatively low number of views in RecyclerListView render tree this should be a non issue.*/
5252
private fun fixLayout() {
5353
if (childCount > 1) {
54-
val positionSortedViews = Array(childCount) { getChildAt(it) as CellContainer }
54+
val positionSortedViews: Array<CellContainer> = Array(childCount) {
55+
val child = getChildAt(it)
56+
if (child is CellContainer) {
57+
child
58+
} else {
59+
throw IllegalStateException("CellRendererComponent outer view should always be CellContainer.")
60+
}
61+
}
5562
positionSortedViews.sortBy { it.index }
5663
alShadow.offsetFromStart = if (alShadow.horizontal) left else top
5764
alShadow.clearGapsAndOverlaps(positionSortedViews)

documentation/docs/fundamentals/usage.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,29 @@ estimatedItemSize: number;
8989

9090
---
9191

92+
### `CellRendererComponent`
93+
94+
Each cell is rendered using this element. Can be a React Component Class, or a render function. The root component should always be a `CellContainer` which is also the default component used. Ensure that the original `props` are passed to the returned `CellContainer`.
95+
96+
When using with `react-native-reanimated`, you can wrap `CellContainer` in `Animated.createAnimatedComponent`:
97+
98+
```ts
99+
const AnimatedCellContainer = Animated.createAnimatedComponent(CellContainer);
100+
return (
101+
<FlashList
102+
CellRendererComponent={(props) => {
103+
return (
104+
<AnimatedCellContainer {...props} style={...}>
105+
);
106+
}}
107+
/>
108+
);
109+
```
110+
111+
```ts
112+
CellRendererComponent?: React.ComponentType<any> | undefined;
113+
```
114+
92115
### `ItemSeparatorComponent`
93116

94117
Rendered in between each item, but not at the top or bottom. By default, `leadingItem` and `trailingItem` (if available) props are provided.
@@ -542,7 +565,6 @@ Param `animated` (`true` by default) defines whether the list should do an anima
542565

543566
The following props from `FlatList` are currently not implemented:
544567

545-
- [`CellRendererComponent`](https://reactnative.dev/docs/virtualizedlist#cellrenderercomponent)
546568
- [`columnWrapperStyle`](https://reactnative.dev/docs/flatlist#columnwrapperstyle)
547569
- [`debug`](https://reactnative.dev/docs/virtualizedlist#debug)
548570
- [`listKey`](https://reactnative.dev/docs/virtualizedlist#listkey)

fixture/ios/Podfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ PODS:
360360
- React-jsi (= 0.68.1)
361361
- React-logger (= 0.68.1)
362362
- React-perflogger (= 0.68.1)
363-
- ReactNativePerformanceListsProfiler (0.0.10):
363+
- ReactNativePerformanceListsProfiler (0.0.11):
364364
- React-Core
365365
- RNFastImage (8.5.11):
366366
- React-Core
@@ -628,7 +628,7 @@ SPEC CHECKSUMS:
628628
React-RCTVibration: 9e344c840176b0af9c84d5019eb4fed8b3c105a1
629629
React-runtimeexecutor: 7285b499d0339104b2813a1f58ad1ada4adbd6c0
630630
ReactCommon: bf2888a826ceedf54b99ad1b6182d1bc4a8a3984
631-
ReactNativePerformanceListsProfiler: 3f9453c24a90c4f77db568d984c48f380968fa0d
631+
ReactNativePerformanceListsProfiler: 7e61653bdfaae62dcec563198df85e2d443c217a
632632
RNFastImage: 1f2cab428712a4baaf78d6169eaec7f622556dd7
633633
RNFlashList: b9b9cad15a69ed4f853315eea89cd73dcc466567
634634
RNGestureHandler: 6e757e487a4834e7280e98e9bac66d2d9c575e9c

fixture/src/twitter/Twitter.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@ import {
66
ActivityIndicator,
77
ViewabilityConfig,
88
} from "react-native";
9-
import { BlankAreaEventHandler, FlashList } from "@shopify/flash-list";
9+
import {
10+
BlankAreaEventHandler,
11+
CellContainer,
12+
FlashList,
13+
} from "@shopify/flash-list";
1014
import { FlashListPerformanceView } from "@shopify/react-native-performance-lists-profiler";
15+
import Animated from "react-native-reanimated";
1116

1217
import { DebugContext } from "../Debug";
1318

ios/Sources/AutoLayoutView.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,17 @@ import UIKit
7777
guard
7878
subviews.count > 1,
7979
// Fixing layout during animation can interfere with it.
80-
layer.animationKeys()?.isEmpty == true
80+
(layer.animationKeys()?.isEmpty ?? true) == true
8181
else { return }
8282
let cellContainers = subviews
83-
.compactMap { $0 as? CellContainer }
83+
.compactMap { subview -> CellContainer? in
84+
if let cellContainer = subview as? CellContainer {
85+
return cellContainer
86+
} else {
87+
assertionFailure(" ")
88+
return nil
89+
}
90+
}
8491
.sorted(by: { $0.index < $1.index })
8592
clearGaps(for: cellContainers)
8693
}

src/FlashList.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
import StickyContainer, { StickyContainerProps } from "recyclerlistview/sticky";
2020

2121
import AutoLayoutView, { BlankAreaEventHandler } from "./AutoLayoutView";
22-
import ItemContainer from "./CellContainer";
22+
import CellContainer from "./CellContainer";
2323
import { PureComponentWrapper } from "./PureComponentWrapper";
2424
import GridLayoutProviderWithProps from "./GridLayoutProviderWithProps";
2525
import CustomError from "./errors/CustomError";
@@ -132,6 +132,14 @@ export interface FlashListProps<T> extends FlatListProps<T> {
132132
| ((info: { viewableItems: ViewToken[]; changed: ViewToken[] }) => void)
133133
| null
134134
| undefined;
135+
136+
/**
137+
* Each cell is rendered using this element.
138+
* Can be a React Component Class, or a render function.
139+
* The root component should always be a `CellContainer` which is also the default component used.
140+
* Ensure that the original `props` are passed to the returned `CellContainer`.
141+
*/
142+
CellRendererComponent?: React.ComponentType<any> | undefined;
135143
}
136144

137145
export interface FlashListState<T> {
@@ -535,8 +543,10 @@ class FlashList<T> extends React.PureComponent<
535543
};
536544

537545
private itemContainer = (props: any, parentProps: any) => {
546+
const CellRendererComponent =
547+
this.props.CellRendererComponent ?? CellContainer;
538548
return (
539-
<ItemContainer
549+
<CellRendererComponent
540550
{...props}
541551
style={{
542552
...props.style,
@@ -553,7 +563,7 @@ class FlashList<T> extends React.PureComponent<
553563
arg={parentProps.index}
554564
renderer={this.getCellContainerChild}
555565
/>
556-
</ItemContainer>
566+
</CellRendererComponent>
557567
);
558568
};
559569

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ export {
2323
export { JSFPSMonitor, JSFPSResult } from "./benchmark/JSFPSMonitor";
2424
export { autoScroll, Cancellable } from "./benchmark/AutoScrollHelper";
2525
export { default as ViewToken } from "./ViewToken";
26+
export { default as CellContainer } from "./CellContainer";

0 commit comments

Comments
 (0)