Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1/2] Make FlatList permissive of ArrayLike data #36236

Closed
wants to merge 1 commit into from

Conversation

NickGerleman
Copy link
Contributor

@NickGerleman NickGerleman commented Feb 22, 2023

Summary:
D38198351 (d574ea3) addedd a guard to FlatList, to no-op if passed data that was not an array. This broke functionality where Realm had documented using Realm.Results with FlatList. Real.Results is an array-like JSI object, but not actually an array, and fails any Array.isArray() checks.

This change loosens the FlatList contract, to explicitly allow array-like non-array entities. The requirement align to Flow $ArrayLike, which allows both arrays, and objects which provide a length, indexer, and iterator.

Though Realm.Results has all the methods of TS ReadonlyArray, RN has generally assumes its array inputs will pass Array.isArray(). This includes any array props still being checked via prop-types.

This change intentionally does not yet change the parameter type of getItemLayout(), which is already too loose (allowing mutable arrays). Changing this is a breaking change, that would be disruptive to backport, so we separate it into a different commit that will be landed as part of 0.72 (see next PR).

Changelog:
[General][Changed] - Make FlatList permissive of ArrayLike data

Differential Revision: D43465654

@facebook-github-bot facebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Facebook Partner: Facebook Partner fb-exported labels Feb 22, 2023
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D43465654

@NickGerleman NickGerleman changed the title Make FlatList permissive of ArrayLike data [1/2] Make FlatList permissive of ArrayLike data Feb 22, 2023
@analysis-bot
Copy link

analysis-bot commented Feb 22, 2023

Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 8,458,851 +29
android hermes armeabi-v7a 7,782,068 +15
android hermes x86 8,934,722 +26
android hermes x86_64 8,791,822 +14
android jsc arm64-v8a 9,093,017 +13
android jsc armeabi-v7a 8,291,067 +9
android jsc x86 9,143,804 +9
android jsc x86_64 9,402,685 -4

Base commit: a2f155f
Branch: main

data &&
(typeof data === 'object' || typeof data === 'function') &&
typeof data.length === 'number' &&
Symbol.iterator in data
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this just to get some proof that it's array-like? I mean, neither the block below nor any other part of the component depends on the data being iterable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, Flow $ArrayLike requires iterability, where TypeScript ArrayLike does not, and I wanted to preemptively avoid the confusion the mismatch would cause and flag anything following the wrong ArrayLike.

But this actually ended up flagging that Flow $ArrayLike requiring iterability is more likely a mistake, and that requirement was added after-the-fact in a separate refactor. So I think it is likely this check will be removed.

Comment on lines 525 to 528
data &&
(typeof data === 'object' || typeof data === 'function') &&
typeof data.length === 'number' &&
Symbol.iterator in data
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest moving this to _checkProps. It seem more like a check for a precondition of the prop than something that needs to be checked potentially multiple times per render: I mean, the call pattern is a discretion of the VirtualizedList component and we don't expect data to change except when the prop updates.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tricky part of that is for compatibility, we cannot trigger an invariant violation like other checks in _checkProps, and instead just want to tell the underlying VirtualizedList not to try to read from the source.

VirtualizedList does assume getItemCount is somewhat cheap, so I agree this checks are a little icky to be adding to be run repeatedly. But it avoids introducing state into the list. I think I should be able to make this check marginally cheaper though.

Summary:
Pull Request resolved: facebook#36236

D38198351 (facebook@d574ea3) addedd a guard to FlatList, to no-op if passed `data` that was not an array. This broke functionality where Realm had documented using `Realm.Results` with FlatList. `Real.Results` is an array-like JSI object, but not actually an array, and fails any `Array.isArray()` checks.

This change loosens the FlatList contract, to explicitly allow array-like non-array entities. The requirement align to Flow `ArrayLike`, which allows both arrays, and objects which provide a length and indexer. Flow `$ArrayLike` currently also requires an iterator, but this is seemingly a mistake in the type definition, and not enforced.

Though `Realm.Results` has all the methods of TS `ReadonlyArray`, RN has generally assumes its array inputs will pass `Array.isArray()`. This includes any array props still being checked [via prop-types](https://github.com/facebook/prop-types/blob/044efd7a108556c7660f6b62092756666e39d74b/factoryWithTypeCheckers.js#L548).

This change intentionally does not yet change the parameter type of `getItemLayout()`, which is already too loose (allowing mutable arrays). Changing this is a breaking change, that would be disruptive to backport, so we separate it into a different commit that will be landed as part of 0.72 (see next diff in the stack).

Changelog:
[General][Changed] - Make FlatList permissive of ArrayLike data

Differential Revision: D43465654

fbshipit-source-id: 73acd565a51dd7dce693fcab9ed06b63284c97df
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D43465654

NickGerleman added a commit to NickGerleman/react-native that referenced this pull request Feb 22, 2023
Summary:
Pull Request resolved: facebook#36236

D38198351 (facebook@d574ea3) addedd a guard to FlatList, to no-op if passed `data` that was not an array. This broke functionality where Realm had documented using `Realm.Results` with FlatList. `Real.Results` is an array-like JSI object, but not actually an array, and fails any `Array.isArray()` checks.

This change loosens the FlatList contract, to explicitly allow array-like non-array entities. The requirement align to Flow `$ArrayLike`, which allows both arrays, and objects which provide a length, indexer, and iterator.

Though `Realm.Results` has all the methods of TS `ReadonlyArray`, RN has generally assumes its array inputs will pass `Array.isArray()`. This includes any array props still being checked [via prop-types](https://github.com/facebook/prop-types/blob/044efd7a108556c7660f6b62092756666e39d74b/factoryWithTypeCheckers.js#L548).

This change intentionally does not yet change the parameter type of `getItemLayout()`, which is already too loose (allowing mutable arrays). Changing this is a breaking change, that would be disruptive to backport, so we separate it into a different commit that will be landed as part of 0.72 (see next diff in the stack).

Changelog:
[General][Changed] - Make FlatList permissive of ArrayLike data

Differential Revision: https://www.internalfb.com/diff/D43465654?entry_point=27

fbshipit-source-id: 15c9e19414b82ea8676df0428c5540097107259c
_getItemCount = (data: ?Array<ItemT>): number => {
if (Array.isArray(data)) {
_getItemCount = (data: ?$ArrayLike<ItemT>): number => {
if (data != null && typeof Object(data).length === 'number') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's ArrayLike obj and not null, it must have a length prop defined. ?
And we don't want those with only size defined or do we ?
any specific reason for new Object instance overhead?

Suggested change
if (data != null && typeof Object(data).length === 'number') {
if (data != null && typeof data.length === 'number') {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per MDN this should return the existing object if it is one, but the check would cause an exception if someone passed say, a number, and the point here has been to guard against invalid data gracefully for legacy reasons.

@facebook-github-bot facebook-github-bot added the Merged This PR has been merged. label Feb 25, 2023
@facebook-github-bot
Copy link
Contributor

This pull request has been merged in c03de97.

kelset pushed a commit that referenced this pull request Mar 6, 2023
Summary:
Pull Request resolved: #36236

D38198351 (d574ea3) addedd a guard to FlatList, to no-op if passed `data` that was not an array. This broke functionality where Realm had documented using `Realm.Results` with FlatList. `Real.Results` is an array-like JSI object, but not actually an array, and fails any `Array.isArray()` checks.

This change loosens the FlatList contract, to explicitly allow array-like non-array entities. The requirement align to Flow `ArrayLike`, which allows both arrays, and objects which provide a length and indexer. Flow `$ArrayLike` currently also requires an iterator, but this is seemingly a mistake in the type definition, and not enforced.

Though `Realm.Results` has all the methods of TS `ReadonlyArray`, RN has generally assumes its array inputs will pass `Array.isArray()`. This includes any array props still being checked [via prop-types](https://github.com/facebook/prop-types/blob/044efd7a108556c7660f6b62092756666e39d74b/factoryWithTypeCheckers.js#L548).

This change intentionally does not yet change the parameter type of `getItemLayout()`, which is already too loose (allowing mutable arrays). Changing this is a breaking change, that would be disruptive to backport, so we separate it into a different commit that will be landed as part of 0.72 (see next diff in the stack).

Changelog:
[General][Changed] - Make FlatList permissive of ArrayLike data

Reviewed By: yungsters

Differential Revision: D43465654

fbshipit-source-id: 3ed8c76c15da680560d7639b7cc43272f3e46ac3
OlimpiaZurek pushed a commit to OlimpiaZurek/react-native that referenced this pull request May 22, 2023
Summary:
Pull Request resolved: facebook#36236

D38198351 (facebook@d574ea3) addedd a guard to FlatList, to no-op if passed `data` that was not an array. This broke functionality where Realm had documented using `Realm.Results` with FlatList. `Real.Results` is an array-like JSI object, but not actually an array, and fails any `Array.isArray()` checks.

This change loosens the FlatList contract, to explicitly allow array-like non-array entities. The requirement align to Flow `ArrayLike`, which allows both arrays, and objects which provide a length and indexer. Flow `$ArrayLike` currently also requires an iterator, but this is seemingly a mistake in the type definition, and not enforced.

Though `Realm.Results` has all the methods of TS `ReadonlyArray`, RN has generally assumes its array inputs will pass `Array.isArray()`. This includes any array props still being checked [via prop-types](https://github.com/facebook/prop-types/blob/044efd7a108556c7660f6b62092756666e39d74b/factoryWithTypeCheckers.js#L548).

This change intentionally does not yet change the parameter type of `getItemLayout()`, which is already too loose (allowing mutable arrays). Changing this is a breaking change, that would be disruptive to backport, so we separate it into a different commit that will be landed as part of 0.72 (see next diff in the stack).

Changelog:
[General][Changed] - Make FlatList permissive of ArrayLike data

Reviewed By: yungsters

Differential Revision: D43465654

fbshipit-source-id: 3ed8c76c15da680560d7639b7cc43272f3e46ac3
@cipolleschi cipolleschi mentioned this pull request Oct 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported Merged This PR has been merged. p: Facebook Partner: Facebook Partner
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants