mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Fix FlatList dark mode examples (#48873)
Summary: - Fix FlatList Nested and Multicolumn dark mode examples - Convert MultiColumn example from class to functional component - Fixing several FlowFixMe annotations for both examples ## Changelog: [INTERNAL] - Fix FlatList dark mode examples Pull Request resolved: https://github.com/facebook/react-native/pull/48873 Test Plan: <details> <summary>Screenshots</summary> | Before | After | |------------------------------------|------------------------------------| |  |  | |  |  | </details> Reviewed By: cortinico Differential Revision: D68630288 Pulled By: Abbondanzo fbshipit-source-id: 41c240e4f8c6e6eacf537d53ab4a06bb0b7ef0de
This commit is contained in:
committed by
Facebook GitHub Bot
parent
c499ae1192
commit
bbd1e0ff17
@@ -14,7 +14,7 @@ import type {Item} from '../../components/ListExampleShared';
|
||||
import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
|
||||
import type {RenderItemProps} from 'react-native/Libraries/Lists/VirtualizedList';
|
||||
|
||||
const {
|
||||
import {
|
||||
FooterComponent,
|
||||
HeaderComponent,
|
||||
ItemComponent,
|
||||
@@ -24,134 +24,64 @@ const {
|
||||
getItemLayout,
|
||||
pressItem,
|
||||
renderSmallSwitchOption,
|
||||
} = require('../../components/ListExampleShared');
|
||||
const RNTesterPage = require('../../components/RNTesterPage');
|
||||
const React = require('react');
|
||||
const {Alert, FlatList, StyleSheet, Text, View} = require('react-native');
|
||||
const infoLog = require('react-native/Libraries/Utilities/infoLog').default;
|
||||
} from '../../components/ListExampleShared';
|
||||
import RNTesterPage from '../../components/RNTesterPage';
|
||||
import RNTesterText from '../../components/RNTesterText';
|
||||
import React from 'react';
|
||||
import {Alert, FlatList, StyleSheet, View} from 'react-native';
|
||||
import infoLog from 'react-native/Libraries/Utilities/infoLog';
|
||||
|
||||
class MultiColumnExample extends React.PureComponent<
|
||||
$FlowFixMeProps,
|
||||
$FlowFixMeState,
|
||||
> {
|
||||
state:
|
||||
| any
|
||||
| {
|
||||
data: Array<Item>,
|
||||
filterText: string,
|
||||
fixedHeight: boolean,
|
||||
logViewable: boolean,
|
||||
numColumns: number,
|
||||
virtualized: boolean,
|
||||
} = {
|
||||
data: genNewerItems(1000),
|
||||
filterText: '',
|
||||
fixedHeight: true,
|
||||
logViewable: false,
|
||||
numColumns: 2,
|
||||
virtualized: true,
|
||||
function MultiColumnExample(): React.Node {
|
||||
const [data, setData] = React.useState(genNewerItems(1000));
|
||||
const [filterText, setFilterText] = React.useState('');
|
||||
const [fixedHeight, setFixedHeight] = React.useState(true);
|
||||
const [logViewable, setLogViewable] = React.useState(false);
|
||||
const [numColumns, setNumColumns] = React.useState(2);
|
||||
const [virtualized, setVirtualized] = React.useState(true);
|
||||
|
||||
const _onChangeFilterText = (_filterText: string) => {
|
||||
setFilterText(_filterText);
|
||||
};
|
||||
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
|
||||
* LTI update could not be added via codemod */
|
||||
_onChangeFilterText = filterText => {
|
||||
this.setState(() => ({filterText}));
|
||||
};
|
||||
_onChangeNumColumns = (numColumns: mixed) => {
|
||||
this.setState(() => ({numColumns: Number(numColumns)}));
|
||||
const _onChangeNumColumns = (_numColumns: mixed) => {
|
||||
setNumColumns(Number(_numColumns));
|
||||
};
|
||||
|
||||
_setBooleanValue: string => boolean => void = key => value =>
|
||||
this.setState({[key]: value});
|
||||
const _setBooleanValue = (key: string) => (value: boolean) => {
|
||||
switch (key) {
|
||||
case 'virtualized':
|
||||
setVirtualized(value);
|
||||
break;
|
||||
case 'fixedHeight':
|
||||
setFixedHeight(value);
|
||||
break;
|
||||
case 'logViewable':
|
||||
setLogViewable(value);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
render(): React.Node {
|
||||
const filterRegex = new RegExp(String(this.state.filterText), 'i');
|
||||
const filter = (item: any | Item) =>
|
||||
filterRegex.test(item.text) || filterRegex.test(item.title);
|
||||
const filteredData = this.state.data.filter(filter);
|
||||
return (
|
||||
<RNTesterPage
|
||||
title={this.props.navigator ? null : '<FlatList> - MultiColumn'}
|
||||
noScroll={true}>
|
||||
<View style={styles.searchRow}>
|
||||
<View style={styles.row}>
|
||||
<PlainInput
|
||||
onChangeText={this._onChangeFilterText}
|
||||
placeholder="Search..."
|
||||
value={this.state.filterText}
|
||||
/>
|
||||
<Text> numColumns: </Text>
|
||||
<PlainInput
|
||||
clearButtonMode="never"
|
||||
onChangeText={this._onChangeNumColumns}
|
||||
value={this.state.numColumns ? String(this.state.numColumns) : ''}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
{renderSmallSwitchOption(
|
||||
'Virtualized',
|
||||
this.state.virtualized,
|
||||
this._setBooleanValue('virtualized'),
|
||||
)}
|
||||
{renderSmallSwitchOption(
|
||||
'Fixed Height',
|
||||
this.state.fixedHeight,
|
||||
this._setBooleanValue('fixedHeight'),
|
||||
)}
|
||||
{renderSmallSwitchOption(
|
||||
'Log Viewable',
|
||||
this.state.logViewable,
|
||||
this._setBooleanValue('logViewable'),
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
<SeparatorComponent />
|
||||
<FlatList
|
||||
ListFooterComponent={FooterComponent}
|
||||
ListHeaderComponent={HeaderComponent}
|
||||
getItemLayout={
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
this.state.fixedHeight ? this._getItemLayout : undefined
|
||||
}
|
||||
data={filteredData}
|
||||
key={this.state.numColumns + (this.state.fixedHeight ? 'f' : 'v')}
|
||||
numColumns={this.state.numColumns || 1}
|
||||
onRefresh={() =>
|
||||
Alert.alert('Alert', 'onRefresh: nothing to refresh :P')
|
||||
}
|
||||
refreshing={false}
|
||||
renderItem={this._renderItemComponent}
|
||||
disableVirtualization={!this.state.virtualized}
|
||||
onViewableItemsChanged={this._onViewableItemsChanged}
|
||||
/>
|
||||
</RNTesterPage>
|
||||
);
|
||||
}
|
||||
_getItemLayout(
|
||||
data: any,
|
||||
index: number,
|
||||
): {
|
||||
length: number,
|
||||
offset: number,
|
||||
index: number,
|
||||
...
|
||||
} {
|
||||
const _getItemLayout = (_data: any, index: number) => {
|
||||
const length =
|
||||
getItemLayout(data, index).length + 2 * (CARD_MARGIN + BORDER_WIDTH);
|
||||
getItemLayout(_data, index).length + 2 * (CARD_MARGIN + BORDER_WIDTH);
|
||||
return {length, offset: length * index, index};
|
||||
}
|
||||
_renderItemComponent = ({item}: RenderItemProps<any | Item>): $FlowFixMe => {
|
||||
};
|
||||
|
||||
const _renderItemComponent = ({
|
||||
item,
|
||||
}: RenderItemProps<any | Item>): $FlowFixMe => {
|
||||
return (
|
||||
<View style={styles.card}>
|
||||
<ItemComponent
|
||||
item={item}
|
||||
fixedHeight={this.state.fixedHeight}
|
||||
onPress={this._pressItem}
|
||||
fixedHeight={fixedHeight}
|
||||
onPress={_pressItem}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
// This is called when items change viewability by scrolling into or out of the viewable area.
|
||||
_onViewableItemsChanged = (info: {
|
||||
const _onViewableItemsChanged = (info: {
|
||||
changed: Array<{
|
||||
key: string,
|
||||
isViewable: boolean,
|
||||
@@ -163,7 +93,7 @@ class MultiColumnExample extends React.PureComponent<
|
||||
...
|
||||
}) => {
|
||||
// Impressions can be logged here
|
||||
if (this.state.logViewable) {
|
||||
if (logViewable) {
|
||||
infoLog(
|
||||
'onViewableItemsChanged: ',
|
||||
info.changed.map(v => ({...v, item: '...'})),
|
||||
@@ -171,18 +101,74 @@ class MultiColumnExample extends React.PureComponent<
|
||||
}
|
||||
};
|
||||
|
||||
_pressItem = (key: string) => {
|
||||
const _pressItem = (key: string) => {
|
||||
const index = Number(key);
|
||||
const itemState = pressItem(this.state.data[index]);
|
||||
this.setState(state => ({
|
||||
...state,
|
||||
data: [
|
||||
...state.data.slice(0, index),
|
||||
itemState,
|
||||
...state.data.slice(index + 1),
|
||||
],
|
||||
}));
|
||||
const itemState = pressItem(data[index]);
|
||||
setData(state => [
|
||||
...state.slice(0, index),
|
||||
itemState,
|
||||
...state.slice(index + 1),
|
||||
]);
|
||||
};
|
||||
|
||||
const filterRegex = new RegExp(String(filterText), 'i');
|
||||
const filter = (item: any | Item) =>
|
||||
filterRegex.test(item.text) || filterRegex.test(item.title);
|
||||
const filteredData = data.filter(filter);
|
||||
|
||||
return (
|
||||
<RNTesterPage title={'<FlatList> - MultiColumn'} noScroll={true}>
|
||||
<View style={styles.searchRow}>
|
||||
<View style={styles.row}>
|
||||
<PlainInput
|
||||
onChangeText={_onChangeFilterText}
|
||||
placeholder="Search..."
|
||||
value={filterText}
|
||||
placeholderTextColor="#000"
|
||||
/>
|
||||
<RNTesterText> numColumns: </RNTesterText>
|
||||
<PlainInput
|
||||
clearButtonMode="never"
|
||||
onChangeText={_onChangeNumColumns}
|
||||
value={numColumns ? String(numColumns) : ''}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
{renderSmallSwitchOption(
|
||||
'Virtualized',
|
||||
virtualized,
|
||||
_setBooleanValue('virtualized'),
|
||||
)}
|
||||
{renderSmallSwitchOption(
|
||||
'Fixed Height',
|
||||
fixedHeight,
|
||||
_setBooleanValue('fixedHeight'),
|
||||
)}
|
||||
{renderSmallSwitchOption(
|
||||
'Log Viewable',
|
||||
logViewable,
|
||||
_setBooleanValue('logViewable'),
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
<SeparatorComponent />
|
||||
<FlatList
|
||||
ListFooterComponent={FooterComponent}
|
||||
ListHeaderComponent={HeaderComponent}
|
||||
getItemLayout={fixedHeight ? _getItemLayout : undefined}
|
||||
data={filteredData}
|
||||
key={numColumns + (fixedHeight ? 'f' : 'v')}
|
||||
numColumns={numColumns || 1}
|
||||
onRefresh={() =>
|
||||
Alert.alert('Alert', 'onRefresh: nothing to refresh :P')
|
||||
}
|
||||
refreshing={false}
|
||||
renderItem={_renderItemComponent}
|
||||
disableVirtualization={virtualized}
|
||||
onViewableItemsChanged={_onViewableItemsChanged}
|
||||
/>
|
||||
</RNTesterPage>
|
||||
);
|
||||
}
|
||||
|
||||
const CARD_MARGIN = 4;
|
||||
|
||||
@@ -9,13 +9,15 @@
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
|
||||
import type {ViewToken} from 'react-native/Libraries/Lists/ViewabilityHelper';
|
||||
import type {RenderItemProps} from 'react-native/Libraries/Lists/VirtualizedList';
|
||||
|
||||
import RNTesterPage from '../../components/RNTesterPage';
|
||||
import RNTesterText from '../../components/RNTesterText';
|
||||
import * as React from 'react';
|
||||
import {useCallback, useEffect, useReducer} from 'react';
|
||||
import {useCallback, useEffect, useMemo, useReducer} from 'react';
|
||||
import {FlatList, StyleSheet, Text, View} from 'react-native';
|
||||
|
||||
type OuterItem = 'head' | 'vertical' | 'horizontal' | 'filler';
|
||||
@@ -77,6 +79,14 @@ function reducer(state: ItemsState, action: ItemsAction): ItemsState {
|
||||
function NestedListExample(): React.Node {
|
||||
const [outer, dispatchOuter] = useReducer(reducer, initialItemsState);
|
||||
const [inner, dispatchInner] = useReducer(reducer, initialItemsState);
|
||||
const sortedInnerViewableItems = useMemo(
|
||||
() => [...inner.viewableItems].sort((a, b) => a - b).join(', '),
|
||||
[inner.viewableItems],
|
||||
);
|
||||
const sortedInnerRenderedItems = useMemo(
|
||||
() => [...inner.renderedItems].sort((a, b) => a - b).join(', '),
|
||||
[inner.renderedItems],
|
||||
);
|
||||
|
||||
const onViewableItemsChanged = useCallback(
|
||||
({
|
||||
@@ -98,38 +108,30 @@ function NestedListExample(): React.Node {
|
||||
|
||||
return (
|
||||
<RNTesterPage noScroll={true}>
|
||||
<Text style={styles.debugText}>
|
||||
<RNTesterText style={styles.debugText}>
|
||||
<Text style={styles.debugTextHeader}>Outer Viewable:{'\n'}</Text>
|
||||
{outerItems
|
||||
.map((item, i) => ({item, i}))
|
||||
.filter(o => outer.viewableItems.includes(o.i))
|
||||
.map(({item, i}) => `${i} (${item})`)
|
||||
.join(', ')}
|
||||
</Text>
|
||||
<Text style={styles.debugText}>
|
||||
</RNTesterText>
|
||||
<RNTesterText style={styles.debugText}>
|
||||
<Text style={styles.debugTextHeader}>Outer Rendered:{'\n'}</Text>
|
||||
{outerItems
|
||||
.map((item, i) => ({item, i}))
|
||||
.filter(o => outer.renderedItems.includes(o.i))
|
||||
.map(({item, i}) => `${i} (${item})`)
|
||||
.join(', ')}
|
||||
</Text>
|
||||
<Text style={styles.debugText}>
|
||||
</RNTesterText>
|
||||
<RNTesterText style={styles.debugText}>
|
||||
<Text style={styles.debugTextHeader}>Inner Viewable:{'\n'}</Text>
|
||||
{
|
||||
// $FlowFixMe[react-rule-hook-mutation]
|
||||
// $FlowFixMe[missing-local-annot]
|
||||
inner.viewableItems.sort((a, b) => a - b).join(', ')
|
||||
}
|
||||
</Text>
|
||||
<Text style={styles.debugText}>
|
||||
{sortedInnerViewableItems}
|
||||
</RNTesterText>
|
||||
<RNTesterText style={styles.debugText}>
|
||||
<Text style={styles.debugTextHeader}>Inner Rendered:{'\n'}</Text>
|
||||
{
|
||||
// $FlowFixMe[react-rule-hook-mutation]
|
||||
// $FlowFixMe[missing-local-annot]
|
||||
inner.renderedItems.sort((a, b) => a - b).join(', ')
|
||||
}
|
||||
</Text>
|
||||
{sortedInnerRenderedItems}
|
||||
</RNTesterText>
|
||||
|
||||
<FlatList
|
||||
data={outerItems}
|
||||
|
||||
Reference in New Issue
Block a user