Skip to content

Commit a53512f

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
VirtualizedList up-to-date state: Thread props to _createViewToken()
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
1 parent e3aad65 commit a53512f

File tree

2 files changed

+21
-6
lines changed

2 files changed

+21
-6
lines changed

Libraries/Lists/ViewabilityHelper.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,11 @@ class ViewabilityHelper {
189189
offset: number,
190190
...
191191
},
192-
createViewToken: (index: number, isViewable: boolean) => ViewToken,
192+
createViewToken: (
193+
index: number,
194+
isViewable: boolean,
195+
props: FrameMetricProps,
196+
) => ViewToken,
193197
onViewableItemsChanged: ({
194198
viewableItems: Array<ViewToken>,
195199
changed: Array<ViewToken>,
@@ -236,6 +240,7 @@ class ViewabilityHelper {
236240
* see the error delete this comment and run Flow. */
237241
this._timers.delete(handle);
238242
this._onUpdateSync(
243+
props,
239244
viewableIndices,
240245
onViewableItemsChanged,
241246
createViewToken,
@@ -247,6 +252,7 @@ class ViewabilityHelper {
247252
this._timers.add(handle);
248253
} else {
249254
this._onUpdateSync(
255+
props,
250256
viewableIndices,
251257
onViewableItemsChanged,
252258
createViewToken,
@@ -269,13 +275,18 @@ class ViewabilityHelper {
269275
}
270276

271277
_onUpdateSync(
278+
props: FrameMetricProps,
272279
viewableIndicesToCheck: Array<number>,
273280
onViewableItemsChanged: ({
274281
changed: Array<ViewToken>,
275282
viewableItems: Array<ViewToken>,
276283
...
277284
}) => void,
278-
createViewToken: (index: number, isViewable: boolean) => ViewToken,
285+
createViewToken: (
286+
index: number,
287+
isViewable: boolean,
288+
props: FrameMetricProps,
289+
) => ViewToken,
279290
) {
280291
// Filter out indices that have gone out of view since this call was scheduled.
281292
viewableIndicesToCheck = viewableIndicesToCheck.filter(ii =>
@@ -284,7 +295,7 @@ class ViewabilityHelper {
284295
const prevItems = this._viewableItems;
285296
const nextItems = new Map(
286297
viewableIndicesToCheck.map(ii => {
287-
const viewable = createViewToken(ii, true);
298+
const viewable = createViewToken(ii, true, props);
288299
return [viewable.key, viewable];
289300
}),
290301
);

Libraries/Lists/VirtualizedList_EXPERIMENTAL.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,13 +1754,17 @@ class VirtualizedList extends React.PureComponent<Props, State> {
17541754
});
17551755
};
17561756

1757-
_createViewToken = (index: number, isViewable: boolean) => {
1758-
const {data, getItem} = this.props;
1757+
_createViewToken = (
1758+
index: number,
1759+
isViewable: boolean,
1760+
props: FrameMetricProps,
1761+
) => {
1762+
const {data, getItem} = props;
17591763
const item = getItem(data, index);
17601764
return {
17611765
index,
17621766
item,
1763-
key: this._keyExtractor(item, index, this.props),
1767+
key: this._keyExtractor(item, index, props),
17641768
isViewable,
17651769
};
17661770
};

0 commit comments

Comments
 (0)