I am working with React native component FlatList there is actually two FlatList one for the dynamic content of Images and the other is using static data. The problem is when i loads that screen static data is loads initially and after that dynamic content loads but when static data loads it occupies the area of dynamic content and when dynamic images are loads they occupy there position and static data stretch to bottom i want to set a position for dynamic data until it loads the area where it will be shown it should be shadow type or something loading skeleton i don't wants that the other FlatList occupy the space of Images while Images are on Loading state.
<FlatList
data={newMovies}
renderItem={({ item, index }) => {
if (index >= 10) {
return null;
}
return (
<View
><Image
resizeMode="cover"
style={{
height: Sizes.DEVICE_HEIGHT * 0.32,
width: Sizes.DEVICE_WIDTH * 0.8875,
zIndex: -100,
marginLeft: 9,
}}
source={{ uri: IMAGE_URL_PREFIX + item.backdrop ||
item.poster }}
/>
<LinearGradient
start={{ x: 0.0, y: 0.0 }}
end={{ x: 0.0, y: 1.2 }}
locations={[0, 0.4, 0.85]}
colors={[Colors.transparent, Colors.transparent,
Colors.black]}
style={{
height: Sizes.DEVICE_HEIGHT * 0.32,
width: Sizes.DEVICE_WIDTH * 0.8875,
marginLeft: 10,
position: 'absolute',
zIndex: 10,
}}
>
<View style={Styles.horizontalImage}>
<Text style={Styles.posterName} numOfLines={1}>
{item.name}</Text>
<Text style={Styles.posterDesc}>
{item.stringAttributes}
</Text>
</View>
</LinearGradient>
</View>
);
}
}
horizontal
onEndReached={() => this.onListEndReached(this.props)}
/>
</View>
<ScrollView style={Styles.innerContainer}>
<FlatList
removeClippedSubviews={false}
data={[{ key: 'New On Netflix', id: 0 },
{ key: 'Watch With Friends', id: 1 },
{ key: 'Watch By Yourself', id: 2 },
{ key: 'Newset Movies', id: 3 },
{ key: 'Best of All Time', id: 4 },
{ key: 'Best On Netflix', id: 5 },
{ key: 'Most Conversational', id: 6 },
{ key: 'Most Rewatchable', id: 7 }]}
renderItem={({ item }) => (<List>
<ListItem style={{ marginLeft: 0 }} onPress={() => this.selection(item.key, item.id)}>
<Text style={Styles.innerheader}>{item.key}</Text>
</ListItem>
</List>)}
keyExtractor={item => item.id}
/>
I found a solution with defining the View around my first FlatList and assigning the with to it exactly to my image so now the other FlatList is not overlapping with it while loading.
Related
I am getting the following error in my implementation of FlatList
A VirtualizedList contains a cell with more than one VirtualizedList of the same orientation as the parent list. You must pass a unique listKey prop to each sibling list.
VirtualizedList trace:
Child (vertical):
listKey: rootList-header
cellKey: rootList-header
Parent (vertical):
listKey: function listKey(item, index) {
return 'createEX' + index.toString();
}
cellKey: rootList
I am also adding relevant code. The code works when I test using expo, although the error comes up. The app crashes in TestFlight.
This is my FlatList Implementation. If I remove the MetNeedsMenu part, the code works.
<FlatList style={stylesCreate.scrollStyle}
listKey={(item, index) => {return 'createEX' + index.toString()}}
ListHeaderComponent={
<View style={stylesCreate.createForm}>
<Text style={styles.screenTitle}>CREATE NEW{"\n"}ENTRY</Text>
<Text style={stylesCreate.label}>How are you feeling now?</Text>
<Dropdown mood={newMoodBefore} setMood={setMoodBefore}/>
<Text style={stylesCreate.label}>Select the areas of life that made you feel grateful.</Text>
<MetNeedsMenu selectedNeeds={needs} setSelectedNeeds={setNeeds}/>
<InfoButton/>
<Text style={stylesCreate.label}>What are you grateful for?</Text>
<GratitudeInput value={newEntry} placeholder="Write Here..." setValue={setEntry}/>
<Text style={stylesCreate.label}>How are you feeling after doing the activity?</Text>
<Dropdown mood={newMoodAfter} setMood={setMoodAfter}/>
<CustomButton text='CREATE' onPress={addEntry}></CustomButton>
</View>
}
>
</FlatList>
This is my MetNeedsMenu implementation.
const K_OPTIONS = [
{
item: 'Physical Wellbeing:',
id: '1',
},
{
item: 'Peace & Calm',
id: '2',
},
{
item: 'Energizing Moments',
id: '3',
},
{
item: 'Engagement / Flow',
id: '4',
},
{
item: 'Connection',
id: '5',
},
{
item: 'Accomplishment',
id: '6',
},
{
item: 'Meaning / Fulfillment',
id: '7',
},
{
item: 'Others',
id: '8',
}
]
const MetNeedsMenu = ({ selectedNeeds, setSelectedNeeds }) => {
return (
<View style={{ marginBottom: 20}}>
<SelectBox
width={300}
label="Select multiple"
options={K_OPTIONS}
selectedValues={selectedNeeds}
onMultiSelect={onMultiChange()}
onTapClose={onMultiChange()}
hideInputFilter={true}
isMulti
listKey={(item, index) => {return index.toString()}}
labelStyle={{
fontSize: 15,
color: '#0060ff',
}}
containerStyle={{
backgroundColor: '#ffffff',
borderRadius: 5,
}}
arrowIconColor={'blue'} //style for dropdown arrow
optionsLabelStyle={{ //style for labels of options
color: 'black',
paddingLeft: 10,
fontSize: 15,
}}
multiOptionContainerStyle={{ //style multiple selections
backgroundColor: '#0060ff',
}}
multiListEmptyLabelStyle={{ //style for SELECT text
paddingLeft: 10,
}}
toggleIconColor={'#0060ff'} //style color of select icon
selectedItemStyle={{
paddingLeft: 10,
}}
/>
</View>
)
function onMultiChange() {
return (item) => setSelectedNeeds(xorBy(selectedNeeds, [item], 'id'))
}
}
I am guessing the problem lies with MultiNeedsMenu, but I have put listKey there with no success
The error tells you that you have a FlatList or Scrollview inside another FlatList or Scrollview with the same orientation. What is possible to do is to have nested FlatList or ScrollView of different orientation. Here is an example:
<FlatList
data={...}
keyExtracto={...}>
<ScrollView horizontal>
<Text>One</Text>
<Text>Two</Text>
</ScrollView>
</FlatList>
I'm using react-native-web and for the Native side, I'm using import { Picker } from '#react-native-picker/picker'
I'm using a reusable form modal for create and edit. On web, the data populates just fine but on iOS for example, the drop downs don't get set correctly. I've created a reusable component that has react-native-picker/picker as it's child component. So for example I set state on form mount like this:
const [languageAbility, setLanguageAbility] = useState<number>(
childProfile?.languageAbility?.id || 0,
)
const [grade, setGrade] = useState<number>(childProfile?.grade?.id || 0)
and on my components, they are set up like this:
<AccessibleSelect
selectedValue={grade}
options={childMenusData?.menus?.schoolGrades.map((sg) => ({
label: sg.title,
value: sg?.id,
}))}
onValueChange={(val: number) => setGrade(val)}
label={t('ChildForms.Grade')}
testID="grade"
inputStyle={styles.selectStyles}
tooltipText={isMobile ? 'What is a grade?' : ''}
tooltipContent={t('ChildForms.WhatIsAGradeContent')}
tooltipPlacement={'bottom'}
/>
</View>
{!isMobile && (
<View style={styles.inputContainerHalf}>
<Tooltip
text="What is a grade?"
content={t('ChildForms.WhatIsAGradeContent')}
placement={'right'}
/>
</View>
)}
</View>
<View
style={{
flexDirection: isMobile ? 'column' : 'row',
width: '100%',
margin: 0,
}}
>
<View
style={[
styles.inputContainerHalf,
{ marginRight: isMobile ? 0 : 30 },
]}
>
<AccessibleSelect
selectedValue={languageAbility}
options={childMenusData?.menus?.languageAbilities.map((la) => ({
label: la.title,
value: la.id,
}))}
onValueChange={(val: number) => setLanguageAbility(val)}
label={t('ChildForms.LanguageAbility')}
testID="languageAbility"
additionalContainerStyles={{ paddingTop: 0, paddingBottom: 0 }}
inputStyle={styles.selectStyles}
/>
</View>
</View>
And the actual Picker component (AccessibleSelect) looks like this:
return (
<View style={[styles.container, additionalContainerStyles]}>
<Picker
ref={refToAttachToInput}
style={[
Platform.OS === 'ios'
? styles.pickerIOS
: [
styles.picker,
{ borderColor, borderStyle: 'solid', borderWidth: 1 },
],
inputStyle,
]}
selectedValue={selectedValue}
onValueChange={onValueChange}
defaultValue={defaultValue && defaultValue}
itemStyle={styles.pickerText}
mode={isAndroid && 'dropdown'}
>
{options.map((o) => (
<Picker.Item label={o.label} key={o.value} value={o.value} />
))}
</Picker>
<View
style={[
styles.bottomContainer,
{ justifyContent: fieldError ? 'space-between' : 'flex-end' },
]}
>
{!!fieldError && (
<Text accessibilityLiveRegion="assertive" style={styles.errorText}>
{fieldError}
</Text>
)}
</View>
</View>
)
}
Displaying more than 200+ images in the flatlist and make the user to select or deselect by clicking an image. So, when the user is clicks a image, Need to show the check-circle icon on the image. Similarly, when the user is deselect the selected image, need to remove the icon. I got two arrays images[] and selectedImagesId[]. Whenever the user selects an image, the image id will be pushed into selectedImagesId array. By the way, Iam showing the icon if the rendered image id avaliable in the selectedImagesId. The problem here is, it takes so long to display or remove the icon.
<FlatList
data={props.images}
extraData={selectedImagesId}
initialNumToRender={10}
refreshing={true}
removeClippedSubviews={true}
maxToRenderPerBatch={1}
windowSize={7}
showsVerticalScrollIndicator={false}
numColumns={3}
keyExtractor={(item) => item.id.toString()}
renderItem={(itemData) => <RenderData itemData={itemData} />}
>
const RenderData = ({ itemData }) => (
<View>
<TouchableOpacity
activeOpacity={0.8}
style={{
width: width / 3.5,
height: height / 7,
padding: 2,
}}
onPress={() => {
console.log('pressed');
if (props.selectedImages.includes(itemData.item.uri)) {
const index = props.selectedImages.indexOf(itemData.item.uri);
if (index > -1) {
props.removeImageandId(index, itemData.item.id);
}
} else {
props.selectImageandId(itemData.item.uri, itemData.item.id);
}
}}>
<Image
style={{ width: '100%', height: '100%' }}
source={{
uri: itemData.item.uri,
}}
/>
{selectedImagesId.includes(itemData.item.id) && (
<AntDesign
name='checkcircle'
size={24}
color='white'
style={{ position: 'absolute', bottom: 5, right: 15 }}
/>
)}
</TouchableOpacity>
<Text style={{ backgroundColor: 'red', fontSize: 25 }}>
{render.current++}
</Text>
</View>
);
You can Refer This article
It will guide you on how to render Only particular selected components that change.
not the Whole flatList components.
so, that based Only selected particular component you can remove the icon. not whole flatList Re-render.
I'm trying to create a ScrollView which contains one sticky selector, that allow the selection between two nested ScollViews. It's like the twitter profile screen, or the instagram screen, where you can switch between my posts and posts where I was tagged.
Now my problem actually is that this two nested ScollViews, let's say "MY POSTS" and "TAGGED" could have different sizes, but the RootScrollView consider only the biggest height of the two scrollviews, so if in the first I've 20 items, and let's say height=1000, in the second if I don't have items, or less items, I'll have an empty space y offset like the first.
I know it's not so clear, but if you open instagram or twitter profile screens you'll immediately get it, the problem of the different heights.
Now as you'll see, what I've tried to do is create a RootScrollView, put inside it two views, the header and the sticky selector, in twitter it's the "Tweet", "Tweets and replies" ... , and the a NestedScrollView which initially has scrollEnabled=false, and then, by scroll the root I'll update it to true and to false the root one. But it seems not to work correctly.
Here's the code:
const HEADER_HEIGHT = height / 3;
const STIKY_SELECTOR_HEIGHT = 100;
const App = () => {
const rootScrollRef = useRef();
const nestedScrollRef = useRef();
const [offset, setOffset] = useState(0);
const [scrollEnabled, setScrollEnabled] = useState(false);
const onRootScroll = ({
nativeEvent: {
contentOffset: { y },
},
}) => {
const direction = y > offset ? "down" : "up";
setOffset(y);
if (y > HEADER_HEIGHT - 10 && direction == "down") {
setScrollEnabled(true);
}
};
const onNestedScroll = ({
nativeEvent: {
contentOffset: { y },
},
}) => {
if (y < 20) setScrollEnabled(false);
};
const renderItem = () => {
return <View style={styles.cell} />;
};
return (
<View style={{ flex: 1 }}>
{/* ROOT SCROLLVIEW */}
<ScrollView
simultaneousHandlers={nestedScrollRef}
scrollEventThrottle={16}
ref={rootScrollRef}
onScroll={onRootScroll}
stickyHeaderIndices={[1]}
scrollEnabled={!scrollEnabled}
style={{ flex: 1, backgroundColor: "gray" }}
>
{/* HEADER */}
<View
style={{ width, height: HEADER_HEIGHT, backgroundColor: "darkblue" }}
></View>
{/* STIKY SELECTOR VIEW */}
<View
style={{ height: STIKY_SELECTOR_HEIGHT, backgroundColor: "red" }}
></View>
{/* NESTED SCROLLVIEW */}
<View style={{ height: height - STIKY_SELECTOR_HEIGHT }}>
<FlatList
data={[1, 2, 3, 4, 5, 6, 7]}
ref={nestedScrollRef}
scrollEventThrottle={16}
onScroll={onNestedScroll}
scrollEnabled={scrollEnabled}
renderItem={renderItem}
numColumns={2}
contentContainerStyle={{
justifyContent: "space-between",
}}
/>
</View>
</ScrollView>
</View>
);
};
If someone is facing the same problem there a component for that react-native-collapsible-tab-view
<Tabs.Container
renderHeader={Header}
headerHeight={HEADER_HEIGHT} // optional>
<Tabs.Tab name="A">
<Tabs.FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={identity}
/>
</Tabs.Tab>
<Tabs.Tab name="B">
<Tabs.ScrollView>
<View style={[styles.box, styles.boxA]} />
<View style={[styles.box, styles.boxB]} />
</Tabs.ScrollView>
</Tabs.Tab>
</Tabs.Container>
Android : 4.4.2 , 8.0
React-native : 0.61.4
It only happens on android.
https://gfycat.com/flimsyastonishingguineafowl
<FlatList
style={{ transform: [{ scaleY: -1 }], marginBottom: 10 }}
removeClippedSubviews
initialNumToRender={20}
data={replyList}
onEndReached={this.nextPage}
contentContainerStyle={{ justifyContent: 'flex-end', flexGrow: 1 }}
keyboardShouldPersistTaps="handled"
pinchGestureEnabled={false}
keyboardDismissMode="none"
keyExtractor={item => `${item.replyUID}reply`}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => (
<RenderReplyItem
item={item}
/>
)}
onScroll={handleScroll}
ref={setRef}
scrollEventThrottle={16}
/>
export default class RenderReplyItem extends PureComponent {
render() {
const {
item,
} = this.props;
return (
<View style={[styles.replyContainer, { alignSelf: 'center', transform: [{ scaleY: -1 }] }]}>
<View style={styles.replyBackground}
>
<Text style={styles.replyContentStyle}
>
{item.content}
</Text>
<View style={styles.replyBottom}>
<Text style={styles.replyregisterDate}>
{item.replyUID}
</Text>
</View>
</View>
</View>
);
}
}
The screen turns white after 80 items have been rendered.
Then scroll down again and the screen will come back and the scroll will move randomly.
Other FlatLists experienced a similar phenomenon and disappeared after setting keyExtractor.
However, only after this page, the same thing happens after you set the keyExtractor.
duplicate of
alternative of flatlist in react-native with much improved performance
For improving flatlist performance tips see here