Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/36236
D38198351 (https://github.com/facebook/react-native/commit/d574ea3526e713eae2c6e20c7a68fa66ff4ad7d2) 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
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/35875
Fixes https://github.com/facebook/react-native/issues/35871
Nested VirtualizedLists register to their parents for updates, associated to a specfific cellKey set by VirtualizedListCellContextProvider. This cellKey is usually set when rendering a cell for a data item, but we can also render a nested VirtualizedList by putting one in a ListHeaderComponent/ListFooterComponent/ListEmptyComponent.
D6603342 (https://github.com/facebook/react-native/commit/a010a0cebd4afc0d88336c2c265a5d9dbb19918f) added cellKeys when we render from a header/footer, but not ListEmptyComponent, so that association would silently fail earlier.
D39466677 (https://github.com/facebook/react-native/commit/010da67bef0c22418d0d41b7c2eae664672a4a27) added extra invariants to child list handling, that are now triggered by this case, complaining because we are trying to unregister a child list we never successfully registered, due to a missing cellKey.
This fixes the issue by providing a cellKey for ListEmptyComponent as well.
Changelog:
[General][Fixed] - Fix invariant violation when nesting VirtualizedList inside ListEmptyComponent
Reviewed By: christophpurrer
Differential Revision: D42574462
fbshipit-source-id: f76fa795bf471cb8a929c2efdbd814ea51927663
# Conflicts:
# Libraries/Lists/VirtualizedList.js
Summary:
Adds some imperative VirtualizedList methods to the TS types which are documented on the website and are public enough. Also explicitly add `viewOffset` to `scrollToItem` since `scrollToItem` params are indefinite in flow and are passed to `scrollToIndex` (which supports the prop).
Changelog:
[General][Fixed] - Add missing VirtualizedList Imperative Types
Reviewed By: GijsWeterings
Differential Revision: D42047674
fbshipit-source-id: 60f7b35b049853d9fcb724918b3a0008a75ea573
Summary:
Breaks the runtime dependency cycle introduced in D40259791 (https://github.com/facebook/react-native/commit/971599317b7bdf1152157206f9503a23ac8c4162) by converting a value import to a type import. (Unlike runtime dependency cycles, type-level cycles are OK as long as they are reasonably small.)
Changelog:
[General][Fixed] - Fix require cycle warning in VirtualizedList
Reviewed By: javache
Differential Revision: D40412019
fbshipit-source-id: 33bf3af12be64a1932549a0d11f2ce8b3c483218
Summary:
`VirtualizedList_EXPERIMENTAL` is a fork of VirtualizedList. It was originally created for the purpose of keyboard/a11y fixes, which required the list to allow rendering discontiguous regions of cells. So, the large part of the refactor is in the data structure used to represent state (now a sparse bitmask), and building out the render function to operate off the bitmask.
This structure allows pre-rendering areas where we know focus must be able to be synchronously be moved to. This is exercised on platforms like Windows and macOS which fire view level focus events. The new implementation otherwise aims to preserve near-exact list behavior as previously.
Apart from the structure change, the refactor has made the code (subjectively) a lot easier to reason about, and there are now stronger internal invariants than before. The bitmask structure also enables new approaches for nested list stability, and implementing OffScreen.
**Why ship it now?**
Having two implementations has multiple times prevented other changes to VirtualizedList, so it is incurring a constant engineer cost.
At this point, we have a lot of reason to be confident in the maturity of the new list implementation (see the test plan below). So, reconciling the implementations not only unlocks the enhancements of the new list, but unblocks future changes to VirtualizedList.
## Test Plan
1. **Unit tests:** A few dozen unit tests were added to VirtualizedList, validating the regions it renders in response to injected input, across its API surface. Both VirtualizedList implementations must pass the same tests, around expected behavior.
2. **RNTester:** Scenarios in RNTester were manually validated, and all worked as before
3. **New invariants:** I added a lot of internal logic checks and bounds checks as invariant violations, to try to produce signal if any part of the refactor went unexpected in the wild.
4. **MSFT Rollout:** I rolled out the changes as a fork of VirtualizedList at MSFT to a couple of high-usage surfaces using Android, iOS, and Windows on Paper. Some invariant violations were surfaced and fixed, but telemetry showed solid system and scenario health with the change.
5. **Meta import:** Fixed all land-blocking test failures when using the new list. These were confined to updating snapshots, and adding additional checks for invalid input.
6. **Panel apps:** Manually validated top-level surfaces of panel apps in debug/release modes. Fixed a couple of invariant violations and novel usages. Profiled new JS structures against an expensive list with Hermes profiler.
7. **Facebook App Rollout:** After some manual validation of top-level surfaces, the change was rolled out to Facebook for Android and iOS as an experiment. New invariant violations were fixed, and the change has sat in production for several weeks at this point, while measuring impact to metrics like error rate, responsiveness, and impressions.
This is the first introduction to all of OSS, and some Meta internal apps. This means there may still be novel usages of VirtualizedList that were not picked up during testing, but I think there has been enough diligence to roll out what has been tested, and forward fix anything unexpected that might still come up.
Changelog:
[General][Changed] - Ship VirtualizedList_EXPERIMENTAL
Reviewed By: javache
Differential Revision: D40259791
fbshipit-source-id: 63eee9381d197a1e38ae663b2158436ff135c0e1
Summary:
Found and removed duplicates of the word "the" in comments.
## Changelog
[Internal] [Removed] – Removed duplicates of the word "the" in comments.
Pull Request resolved: https://github.com/facebook/react-native/pull/34807
Test Plan: Not applicable.
Reviewed By: yungsters, cipolleschi
Differential Revision: D39880587
fbshipit-source-id: b7277aa70604902929903c31ab69d4c532f2667a
Summary:
React Native's TS definitions are currently mostly stored in one monolithic file. This change splits the definitions up to correspond to the source files they came from, and are placed next to the source files. I think this should help inform, and make it easy to update the TS declarations when touching the Flow file.
I noticed as part of the change that the typings have not yet removed many APIs that were removed from RN. This is bad, since it means using the removed/non-functional API doesn't cause typechecker errors. Locating typings next to source should prevent that from being able to happen.
The organization here means individual TS declarations can declare what will be in the RN entrypoint, which is a little confusing. Seems like a good potential next refactor, beyond the literal translation I did.
Changelog:
[General][Changed] - Place TS Declarations Alongside Source Files
Reviewed By: lunaleaps, rshest
Differential Revision: D39796598
fbshipit-source-id: b36366466fd1976bdd2d4c8f7a4104a33c457a07
Summary:
`verifyVirtualizedList` chokes on missing displayName in DEV, due to a mistake in D39648806 (https://github.com/facebook/react-native/commit/a0d1585cdb5ae86e5d4e5bc51fdfa9ae7e049b4b). Not sure why this isn't triggered in Jest tests (maybe it is able to fill displayName via transform?), but this fixes the issue in dev mode.
Changelog:
[Internal][Fixed] - Fix crash in DEV when VirtualizedList_EXPERIMENTAL is loaded
Reviewed By: mdvacca
Differential Revision: D39670991
fbshipit-source-id: b1a784aa3fffdc5f2f025eb1f689307132aad9b6
Summary:
VirtualizedList uses a combination of ES6 and CommonJS imports/exports. This moves fully to ES6 imports and exports, in the experimental version (which should soon replace the original).
Changelog:
[Internal][Changed] - Move VirtualizedList_EXPERIMENTAL to ES6 import/export
Reviewed By: rshest
Differential Revision: D39648806
fbshipit-source-id: a5da40f62a6010cd5b9894b02a91af86d3a8b995
Summary:
VirtualizedList is large and complicated, getting larger and more complicated. This splits out a subcomponent, the cell renderer into its own file, since it is relatively isolated already. This uses the copy from VirtualizedList_EXPERIMENTAL, whose only real difference is exposing focus capture events to the containing VirtualizedList.
Changelog:
[Internal][Changed] - Extract VirtualizedListCellRenderer
Reviewed By: rshest
Differential Revision: D39648087
fbshipit-source-id: bb7c2eff0c658713c256650596f86e8788019baf
Summary:
Now that the prop noops, remove the usages of the property. This is the point of no return for the prop.
Replaced listKey usage with a combination of `flow check`, regex replace, manual inspection.
Changelog:
[General][Removed] - Remove usages of listKey
Reviewed By: fred2028
Differential Revision: D39589089
fbshipit-source-id: 722ebb7dce038a2709656394b7d736e72f488bb7
Summary:
Following up on the previous diff to remove the only usage of `listKey` for persistent association, we can remove the need for a manual `listKey`, and instead rely on per-instance association via refs.
A followup change will remove the existing usages.
Changelog:
[General][Removed] - Remove VirtualizedList `listKey` prop
Reviewed By: p-sun
Differential Revision: D39466677
fbshipit-source-id: 6b49f45c987fff9836918ba833fbb16f24414ff8
Summary:
When `getItemLayout` is not supplied, VirtualizedList doesn't know the measurements for its child items ahead of time. It caches most recent cell measurements so that an item which is virtualized away is associated with its correct height. VirtualizedList will not consume space for an item it has not yet rendered/knows measurements for.
This also means an initially created list will only take up the height of its `initialNumToRender()`. This can cause scroll jumping for the scenario of nested VirtualizedLists of the same orientation, since a virtualized away child list will shrink (compared to the spacer), then re-expand, once returned to.
There is logic in the VirtualizedList constructor to load cached frame metrics based on supplied listKey, to enable reloading most recent state. Though locally it seems to be reading the context too early in the lifecycle (compared to other successful checks during componentDidMount, render). It was moved from `componentDidMount` to `constructor` as part of the initial change (https://www.internalfb.com/diff/D6330846 (https://github.com/facebook/react-native/commit/2668dc8e1be7bf93e65ca2e11c87cbeef3310c3e)?dst_version_fbid=131968984136932&transaction_fbid=1578362385612542), and I think has likely been unreliable or dead since.
Restoring state was the only usage of a durable key for nested lists beyond their lifetime. So removing the dead code lets us remove the need for a `listKey`, which has been error-prone. This still leaves the problem present since inception, but there may be alternate solutions like scroll anchoring.
Changelog:
[Internal][Removed] - Remove dead code for restoring state to nested VirtualizedList
Reviewed By: ryancat
Differential Revision: D39466678
fbshipit-source-id: fc2f39802e5cdf9b920974333be64c74211b99a9
Summary:
This adds a a couple of tests to run existing behavior where VirtualizedList avoids batched renders until it has seen scroll metrics when the list is not initialized to the zero position.
Changelog:
[Internal][Added] - Add VirtualizedList tests for handling non-zero initialScrollIndex before scroll metrics
Reviewed By: yungsters
Differential Revision: D39247250
fbshipit-source-id: 530f58f9c7421949c388048c376fc5b0ab7835d9
Summary:
This replaces all direct references to `ReactNative` within the `react-native` package to use `findNodeHandle` with a reference obtained from `RendererProxy`, which will allow us to select the correct renderer.
Changelog: [internal]
Reviewed By: javache
Differential Revision: D39270689
fbshipit-source-id: a39875281ba7b7b1b00128564124b6adcacebc4d
Summary:
FillRateHelper accesses frame metrics based on passed state/cellsAroundViewport on scroll. cellsAroundViewport may be [0, -1] for no items. Usually this is captured by the check that item count is zero, but it is possible to have items without yet expanding state to render the items. This adds a check to bail early if we are not yet rendering any viewport-related cells.
Also renamed "state" to "cellsAroundViewport" for more consistent naming with the new list, where it is no longer the only state.
Reviewed By: javache
Differential Revision: D39345705
fbshipit-source-id: 198ab46ff2c8e8fe64076c9150edd4914dd745d7
Summary: VirtualizedList would more gracefully handle out of range cells than VirtualizedList_EXPERIMENTAL, which treats it as an invariant violation. D39244112 (https://github.com/facebook/react-native/commit/7aa203beda3cd358703c2fa535ed045771761612) attempted to fix an issue where recalculation of cells around viewport can include out of range cells, but it is still showing up later. This change adds a bounds check to the remaining branch we control, and an assertion that `computeWindowedRenderLimits` is not returing something out of range to discover if that is the cause.
Reviewed By: yungsters
Differential Revision: D39267445
fbshipit-source-id: 64c99da28b5b01ef61784079b586e355f73764a1
Summary:
Non-integer `initialScrollIndex` or values to `scrollToIndex` would produce a reasonable result, with the caveat that it always falls back to layout estimation (will only be correct when all items are the same size), and breaks if getItemLayout() is supplied. It has usage though, so this diff adds proper support for non-integer scrollIndex, to offset a given amount into the length of the specific cell.
This overlaps a bit with the optional `viewOffset` and `viewPosition` arguments in `scrollToIndex`, but there isn't really the equivalent API for `initialScrollIndex`.
Changelog:
[General][Added]- Add proper support for fractional scrollIndex in VirtualizedList
Reviewed By: yungsters
Differential Revision: D39271100
fbshipit-source-id: 4d93887eed4497e9f6abcd1a6117ac7fdaebf2b1
Summary: VirtualizedList would more gracefully handle out of range cells than VirtualizedList_EXPERIMENTAL, which treats it as an invariant violation. This attempts to fix an issue where recalculation of cells around viewport can include out of range cells.
Reviewed By: rshest
Differential Revision: D39244112
fbshipit-source-id: 20fe6ea552035061d9d00720fcab77b29a785771
Summary:
Cleans up a few minor Flow suppression comments in `FlatList`. This reveals a new Flow error that is the result of `FlatList`'s props object being inexact whereas `VirtualizedList`'s props object is exact. For now, I introduce another -- but more specific -- Flow suppression for that type error.
The code changes should not have any consequential behavior change.
Changelog:
[Internal]
Reviewed By: NickGerleman
Differential Revision: D38646228
fbshipit-source-id: f4f9b0ad95323157ff1519353b38e8486adc841d
Summary:
This diff is part of an overall stack, meant to fix incorrect usage of `setState()` in `VirtualizedList`, which triggers new invariant checks added in `VirtualizedList_EXPERIMENTAL`. See the stack summary below for more information on the broader change.
## Diff Summary
This adds a `StateSafePureComponent`, which will override `setState`, along with `this.props` and `this.state`, in order to add runtime enforcement that `this.props` and `this.state` are not accessed during a state update where we should be relying on parameter instead. This should be landed after the fixes for unsafe `this.props`/`this.state` usage.
## Stack Summary
`VirtualizedList`'s component state is a set of cells to render. This state is set via the `setState()` class component API. The main "tick" function `VirtualizedList._updateCellsToRender()` calculates this new state using a combination of the current component state, and instance-local state like maps, measurement caches, etc.
From: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
---
> React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state. For example, this code may fail to update the counter:
```
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
```
> To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
```
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
```
---
`_updateCellsToRender()` transitively calls many functions which will read directly from `this.props` or `this.state` instead of the value passed by the state updater. This intermittently fires invariant violations, when there is a mismatch.
This diff migrates all usages of `props` and `state` during state update to the values provied in `setState()`. To prevent future mismatch, and to provide better clarity on when it is safe to use `this.props`, `this.state`, I overrode `setState` to fire an invariant violation if it is accessed when it is unsafe to:
{F756963772}
Changelog:
[Internal][Changed] - Enable setState() hooks
Reviewed By: rshest
Differential Revision: D38294338
fbshipit-source-id: d04ff39f68df90adc9f4680887d308d997903675
Summary:
Fixes https://github.com/facebook/react-native/issues/34034.
The FlatList doesn't call renderItem on nullish values when numColumns > 1, but it does when numColumns is not set (or equals 1).
I think the behavior should be consistent, so I updated the code so renderItems is called for every items.
I believe the condition `item != null` was here to make sure renderItem isn't called for index outside of data range, so I replaced it with `itemIndex < data.length`.
## Changelog
<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->
[General] [Fixed] - Fix FlatList not calling render items for nullish values when numColumns > 1
Pull Request resolved: https://github.com/facebook/react-native/pull/34205
Test Plan:
- I added a failing test corresponding to the issue, and the test now succeeds.
- I used the same code as in the test on a newly initialized app on RN 0.69 and made sure renderItem was called for every items as expected.
Reviewed By: NickGerleman
Differential Revision: D38185103
Pulled By: lunaleaps
fbshipit-source-id: 4baa55caef9574c91c43c047f9e419016ceb39db
Summary:
This diff is part of an overall stack, meant to fix incorrect usage of `setState()` in `VirtualizedList`, which triggers new invariant checks added in `VirtualizedList_EXPERIMENTAL`. See the stack summary below for more information on the broader change.
## Diff Summary
`_createViewToken()` is called during state changes. Use explicit props passed in.
## Stack Summary
`VirtualizedList`'s component state is a set of cells to render. This state is set via the `setState()` class component API. The main "tick" function `VirtualizedList._updateCellsToRender()` calculates this new state using a combination of the current component state, and instance-local state like maps, measurement caches, etc.
From: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
---
> React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state. For example, this code may fail to update the counter:
```
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
```
> To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
```
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
```
---
`_updateCellsToRender()` transitively calls many functions which will read directly from `this.props` or `this.state` instead of the value passed by the state updater. This intermittently fires invariant violations, when there is a mismatch.
This diff migrates all usages of `props` and `state` during state update to the values provied in `setState()`. To prevent future mismatch, and to provide better clarity on when it is safe to use `this.props`, `this.state`, I overrode `setState` to fire an invariant violation if it is accessed when it is unsafe to:
{F756963772}
Changelog:
[Internal][Fixed] - Thread props to _createViewToken()
Reviewed By: genkikondo
Differential Revision: D38294339
fbshipit-source-id: dc215e267f126a3789742c14c35479f509822710
Summary:
This diff is part of an overall stack, meant to fix incorrect usage of `setState()` in `VirtualizedList`, which triggers new invariant checks added in `VirtualizedList_EXPERIMENTAL`. See the stack summary below for more information on the broader change.
## Diff Summary
`_onCellFocusCapture()` derives state from existing state, so it should be wrapped in a state updater to compare against the latest value in the batch.
## Stack Summary
`VirtualizedList`'s component state is a set of cells to render. This state is set via the `setState()` class component API. The main "tick" function `VirtualizedList._updateCellsToRender()` calculates this new state using a combination of the current component state, and instance-local state like maps, measurement caches, etc.
From: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
---
> React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state. For example, this code may fail to update the counter:
```
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
```
> To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
```
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
```
---
`_updateCellsToRender()` transitively calls many functions which will read directly from `this.props` or `this.state` instead of the value passed by the state updater. This intermittently fires invariant violations, when there is a mismatch.
This diff migrates all usages of `props` and `state` during state update to the values provied in `setState()`. To prevent future mismatch, and to provide better clarity on when it is safe to use `this.props`, `this.state`, I overrode `setState` to fire an invariant violation if it is accessed when it is unsafe to:
{F756963772}
Changelog:
[Internal][Fixed] - Use correct form of setState() in _onCellFocusCapture()
Reviewed By: genkikondo
Differential Revision: D38293583
fbshipit-source-id: 1d0e5152e6c1757408e39dff225e07accc5ee49f
Summary:
This diff is part of an overall stack, meant to fix incorrect usage of `setState()` in `VirtualizedList`, which triggers new invariant checks added in `VirtualizedList_EXPERIMENTAL`. See the stack summary below for more information on the broader change.
## Diff Summary
Use supplied props in `_keyExtractor()`, which is used to map between frame index and identity.
## Stack Summary
`VirtualizedList`'s component state is a set of cells to render. This state is set via the `setState()` class component API. The main "tick" function `VirtualizedList._updateCellsToRender()` calculates this new state using a combination of the current component state, and instance-local state like maps, measurement caches, etc.
From: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
---
> React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state. For example, this code may fail to update the counter:
```
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
```
> To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
```
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
```
---
`_updateCellsToRender()` transitively calls many functions which will read directly from `this.props` or `this.state` instead of the value passed by the state updater. This intermittently fires invariant violations, when there is a mismatch.
This diff migrates all usages of `props` and `state` during state update to the values provied in `setState()`. To prevent future mismatch, and to provide better clarity on when it is safe to use `this.props`, `this.state`, I overrode `setState` to fire an invariant violation if it is accessed when it is unsafe to:
{F756963772}
Changelog:
[Internal][Fixed] - Thread props to _keyExtractor()
Reviewed By: genkikondo
Differential Revision: D38293586
fbshipit-source-id: e50823bacdf45adad3b8b655d66d305a1762e9b8
Summary:
This diff is part of an overall stack, meant to fix incorrect usage of `setState()` in `VirtualizedList`, which triggers new invariant checks added in `VirtualizedList_EXPERIMENTAL`. See the stack summary below for more information on the broader change.
## Diff Summary
This forwards props to `__getFrameMetricsApprox()` and `_getFrameMetrics()` . This is called in a variery of places, so we need to pass `FrameMetricProps` through more places, and update public/test usage.
## Stack Summary
`VirtualizedList`'s component state is a set of cells to render. This state is set via the `setState()` class component API. The main "tick" function `VirtualizedList._updateCellsToRender()` calculates this new state using a combination of the current component state, and instance-local state like maps, measurement caches, etc.
From: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
---
> React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state. For example, this code may fail to update the counter:
```
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
```
> To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
```
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
```
---
`_updateCellsToRender()` transitively calls many functions which will read directly from `this.props` or `this.state` instead of the value passed by the state updater. This intermittently fires invariant violations, when there is a mismatch.
This diff migrates all usages of `props` and `state` during state update to the values provied in `setState()`. To prevent future mismatch, and to provide better clarity on when it is safe to use `this.props`, `this.state`, I overrode `setState` to fire an invariant violation if it is accessed when it is unsafe to:
{F756963772}
Changelog:
[Internal][Fixed] - Thread props to __getFrameMetrics()
Reviewed By: genkikondo
Differential Revision: D38293591
fbshipit-source-id: c1499d722b69eb4b5953124ee8b8c3d15e912d93
Summary:
This diff is part of an overall stack, meant to fix incorrect usage of `setState()` in `VirtualizedList`, which triggers new invariant checks added in `VirtualizedList_EXPERIMENTAL`. See the stack summary below for more information on the broader change.
## Diff Summary
Use passed props in `computeWindowedRenderLimits()`, which is called during a state update.
## Stack Summary
`VirtualizedList`'s component state is a set of cells to render. This state is set via the `setState()` class component API. The main "tick" function `VirtualizedList._updateCellsToRender()` calculates this new state using a combination of the current component state, and instance-local state like maps, measurement caches, etc.
From: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
---
> React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state. For example, this code may fail to update the counter:
```
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
```
> To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
```
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
```
---
`_updateCellsToRender()` transitively calls many functions which will read directly from `this.props` or `this.state` instead of the value passed by the state updater. This intermittently fires invariant violations, when there is a mismatch.
This diff migrates all usages of `props` and `state` during state update to the values provied in `setState()`. To prevent future mismatch, and to provide better clarity on when it is safe to use `this.props`, `this.state`, I overrode `setState` to fire an invariant violation if it is accessed when it is unsafe to:
{F756963772}
Changelog:
[Internal][Fixed] - Thread props to computeWindowedRenderLimits()
Reviewed By: genkikondo
Differential Revision: D38293588
fbshipit-source-id: 1330a003c1354bbd63c0b7b33a013e85e96fdc64
Summary:
This diff is part of an overall stack, meant to fix incorrect usage of `setState()` in `VirtualizedList`, which triggers new invariant checks added in `VirtualizedList_EXPERIMENTAL`. See the stack summary below for more information on the broader change.
## Diff Summary
Change `_updateViewableItems()` to accept an explicit set of props, and a CellRenderMask, instead of using `this.props` and `this.state`. The eventual sink are the `_getFrameMetric*` functions, so a minimal projection of props is added that we can pass through to it.
## Stack Summary
`VirtualizedList`'s component state is a set of cells to render. This state is set via the `setState()` class component API. The main "tick" function `VirtualizedList._updateCellsToRender()` calculates this new state using a combination of the current component state, and instance-local state like maps, measurement caches, etc.
From: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
---
> React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state. For example, this code may fail to update the counter:
```
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
```
> To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
```
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
```
---
`_updateCellsToRender()` transitively calls many functions which will read directly from `this.props` or `this.state` instead of the value passed by the state updater. This intermittently fires invariant violations, when there is a mismatch.
This diff migrates all usages of `props` and `state` during state update to the values provied in `setState()`. To prevent future mismatch, and to provide better clarity on when it is safe to use `this.props`, `this.state`, I overrode `setState` to fire an invariant violation if it is accessed when it is unsafe to:
{F756963772}
Changelog:
[Internal][Changed] - Move Props to VirtualizedListProps
Reviewed By: genkikondo
Differential Revision: D38293587
fbshipit-source-id: 164fd4af7c370d905af53b0e9aafb3592d8659cc
Summary:
This diff is part of an overall stack, meant to fix incorrect usage of `setState()` in `VirtualizedList`, which triggers new invariant checks added in `VirtualizedList_EXPERIMENTAL`. See the stack summary below for more information on the broader change.
## Diff Summary
Remove `this.props` usage during state update where we can just use the props directly.
## Stack Summary
`VirtualizedList`'s component state is a set of cells to render. This state is set via the `setState()` class component API. The main "tick" function `VirtualizedList._updateCellsToRender()` calculates this new state using a combination of the current component state, and instance-local state like maps, measurement caches, etc.
From: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
---
> React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state. For example, this code may fail to update the counter:
```
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
```
> To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
```
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
```
---
`_updateCellsToRender()` transitively calls many functions which will read directly from `this.props` or `this.state` instead of the value passed by the state updater. This intermittently fires invariant violations, when there is a mismatch.
This diff migrates all usages of `props` and `state` during state update to the values provied in `setState()`. To prevent future mismatch, and to provide better clarity on when it is safe to use `this.props`, `this.state`, I overrode `setState` to fire an invariant violation if it is accessed when it is unsafe to:
{F756963772}
Changelog:
[Internal][Fixed] - Remove _isVirtualizationDisabled()
Reviewed By: genkikondo
Differential Revision: D38293589
fbshipit-source-id: af18f867fc880d5363134fe0d6f985efaf8be6c5
Summary:
This diff is part of an overall stack, meant to fix incorrect usage of `setState()` in `VirtualizedList`, which triggers new invariant checks added in `VirtualizedList_EXPERIMENTAL`. See the stack summary below for more information on the broader change.
## Diff Summary
This moves public VirtualizedList types to a new file, shared between both `VirtualizedList`, and `VirtualizedList_EXPERIMENTAL`. This allows us to make public interface changes in a single place.
## Stack Summary
`VirtualizedList`'s component state is a set of cells to render. This state is set via the `setState()` class component API. The main "tick" function `VirtualizedList._updateCellsToRender()` calculates this new state using a combination of the current component state, and instance-local state like maps, measurement caches, etc.
From: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
---
> React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state. For example, this code may fail to update the counter:
```
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
```
> To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
```
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
```
---
`_updateCellsToRender()` transitively calls many functions which will read directly from `this.props` or `this.state` instead of the value passed by the state updater. This intermittently fires invariant violations, when there is a mismatch.
This diff migrates all usages of `props` and `state` during state update to the values provied in `setState()`. To prevent future mismatch, and to provide better clarity on when it is safe to use `this.props`, `this.state`, I overrode `setState` to fire an invariant violation if it is accessed when it is unsafe to:
{F756963772}
Changelog:
[Internal][Changed] - Move Props to VirtualizedListProps
Reviewed By: genkikondo
Differential Revision: D38293585
fbshipit-source-id: 344d94466a2741ee67eb5754de5506eb3e265c5b
Summary:
This diff is part of an overall stack, meant to fix incorrect usage of `setState()` in `VirtualizedList`, which triggers new invariant checks added in `VirtualizedList_EXPERIMENTAL`. See the stack summary below for more information on the broader change.
## Diff Summary
Replace usages of `this.state` and `this.props` where we are already passed the newer revision of the state we want.
## Stack Summary
`VirtualizedList`'s component state is a set of cells to render. This state is set via the `setState()` class component API. The main "tick" function `VirtualizedList._updateCellsToRender()` calculates this new state using a combination of the current component state, and instance-local state like maps, measurement caches, etc.
From: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
---
> React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state. For example, this code may fail to update the counter:
```
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
```
> To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
```
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
```
---
`_updateCellsToRender()` transitively calls many functions which will read directly from `this.props` or `this.state` instead of the value passed by the state updater. This intermittently fires invariant violations, when there is a mismatch.
This diff migrates all usages of `props` and `state` during state update to the values provied in `setState()`. To prevent future mismatch, and to provide better clarity on when it is safe to use `this.props`, `this.state`, I overrode `setState` to fire an invariant violation if it is accessed when it is unsafe to:
{F756963772}
Changelog:
[Internal][Fixed] - Remove bad usage in _adjustCellsAroundViewport()
Reviewed By: genkikondo
Differential Revision: D38293584
fbshipit-source-id: 807f36600d2fd82c87205195dd61956785bdbd2c
Summary:
VirtualizedList state is represented in terms of [first, last] ranges, where it is possible to express a zero-cell range by having [n, n-1]. This includes some awkward examples, like [0, -1] being valid.
CellRenderMask assumes `addCells` is called with at least one cell, with VirtualizedList previously guarding against adding the no cell case. This guard is present for adding main cell regions, but not for `_initialRenderRegion()`, which can be overridden to have a zero length as well.
This moves the `CellRenderMask` to be permissive of zero-length cell regions, and removes the caller guard.
Changelog:
[Internal][Fixed] - Allow empty cell ranges in CellRenderMask
Reviewed By: rshest
Differential Revision: D38184444
fbshipit-source-id: d2dadfdd9628b24f894126d63b1eb93f6387b877
Summary:
Existing code may pass negative values for `initialScrollIndex`, which the previous implemnentation handled gracefully. Handle the case gracefully in VirtualizedList_EXPERIMENTAL as well.
Changelog:
[Internal][Fixed] - Gracefully handle negative initialScrollIndex in VirtualizedList_EXPERIMENTAL
Reviewed By: rshest
Differential Revision: D38183625
fbshipit-source-id: 9aea91c4cf3ce2190d769f34ce728a109efc88d4