Remove horizontal line from last item in react-native - react-native

I have a map which loop all items in the products object and output each new items, What i want is to remove the red line under the "product 003", which is the last item.
Image
const App = () => (
<View style={styles.container}>
{products.map((product, index) => (
<ShoppingList key={index} title={product.title} price={product.price} />
))}
</View>
);
const ShoppingList = props => {
return (
<View style={styles.line}>
<Text>{props.title}</Text>
<Text>{props.price}</Text>
</View>
);
};
const products = [
{
title: 'Product 001',
price: '100000',
},
{
title: 'Product 002',
price: '20000',
},
{
title: 'Product 003',
price: '10000',
},
];
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 24,
},
line: {
padding: 4,
borderBottomColor: 'red',
borderBottomWidth: StyleSheet.hairlineWidth,
},
});

Either use the index provided in the .map loop
{products.map((product, index) => (
(index === products.length) ? <ItemWithoutHorizontalLine /> : <ItemWithHorizontalLine />
))}
or use a VirtualizedList (or any of the child components of VirtualizedList e.g., FlatList) and provide a ItemSeparatorComponent
<FlatList
...
ItemSeparatorComponent={this.renderSeparator}
</FlatList>

Related

FlatList inside SectionList

I have screen with 3 different Lists, all lists have some custom header/footer and Lists contain big amount of data, so my question is - is there any performance issue with FlatList inside of SectionList?
This is rough example what i want to do
const App = () => {
const renderItem = ({item, section, index}) => {
switch (section.type) {
case 'LIST_1':
return (
<View>
<Text>Some custom set of components</Text>
<FlatList
data={section.items}
renderItem={({item}) => (
<View
style={{
padding: 20,
margin: 10,
backgroundColor: 'blue',
}}>
<Text>{item.title}</Text>
</View>
)}
keyExtractor={item => item.id}
/>
</View>
);
case 'LIST_2':
return (
<View>
<Text>Some custom set of components</Text>
<FlatList
data={section.items}
renderItem={({item}) => (
<View
style={{
padding: 20,
margin: 10,
backgroundColor: 'red',
}}>
<Text>{item.count}</Text>
</View>
)}
keyExtractor={item => item.id}
/>
</View>
);
case 'LIST_3':
return (
<View>
<Text>Some custom set of components</Text>
<FlatList
data={section.items}
renderItem={({item}) => (
<View
style={{
padding: 20,
margin: 10,
backgroundColor: 'blue',
}}>
<Text>{item.score}</Text>
</View>
)}
keyExtractor={item => item.id}
/>
</View>
);
}
};
const sections = [
{
type: 'LIST_1',
data: [1],
items: Array.from(Array(50)).map((el, i) => ({
id: i + 1,
title: i + 1,
})),
},
{
type: 'LIST_2',
data: [2],
items: Array.from(Array(50)).map((el, i) => ({
id: i + 1,
count: i + 1,
})),
},
{
type: 'LIST_3',
data: [3],
items: Array.from(Array(50)).map((el, i) => ({
id: i + 1,
score: i + 1,
})),
},
];
return (
<SafeAreaView>
<SectionList
sections={sections}
keyExtractor={item => item}
renderItem={renderItem}
/>
</SafeAreaView>
);
};
If this is not optimal solution and ScrollView takes a lot of time to render, Can you guide me what is better?
Your example can be achieved simply by using SectionList.
// Here we define section objects. I arbitrarily added title, footer and style.
const DATA = [
{
title: 'Section 1 header',
footer: 'Section 1 footer',
data: [...Array(3).keys()],
style: { backgroundColor: 'red' },
},
{
title: 'Section 2 header',
footer: 'Section 2 footer',
data: [...Array(3).keys()],
style: { backgroundColor: 'blue' },
},
{
title: 'Section 3 header',
footer: 'Section 3 footer',
data: [...Array(3).keys()],
style: { backgroundColor: 'yellow' },
},
]
// renderItem gets passed an object with item, section, index and separator keys. I'm using item and section to access my own section style.
const Item = ({ item, sectionStyle }) => (
<View style={[styles.item, sectionStyle]}>
<Text style={styles.title}>{item}</Text>
</View>
)
// Use renderSectionHeader and renderSectionFooter props to add, respectively, header and footer.
const App = () => (
<SafeAreaView style={styles.container}>
<SectionList
sections={DATA}
keyExtractor={(item, index) => item + index}
renderItem={({ item, section }) => <Item item={item} sectionStyle={section.style} />}
renderSectionHeader={({ section: { title } }) => <Text style={styles.header}>{title}</Text>}
renderSectionFooter={({ section: { footer } }) => <Text style={styles.header}>{footer}</Text>}
/>
</SafeAreaView>
)
And to answer your original question, you might run into performance issues with react-natives list components, it depends on many factors, including your data and rendered components.
You can read more on the topic here:
https://reactnative.dev/docs/optimizing-flatlist-configuration

In react-native-autocomplete-dropdown, using 2 dropdowns only 1 visible at a time (user toggles view), only onChangeText of 1st dropdown is firing

Context:
In a single screen view, there are 2 dropdowns (made using react-native-autocomplete-dropdown) but only 1 is visible at a time. The other dropdown comes into view when the user toggles the next tab. I am using react hooks and the component is a functional component. Also, I am new to react hooks.
Issue:
When I try to search on the 2nd dropdown, I expect the onChangeText function of the 2nd dropdown to fire but it fires the function of the 1st dropdown.
Source arrays:
const allYards = [{ id: "1", name: "Java" }, { id: "2", name: "React" }, { id: "3", name: "Angular" }];
const [yards, setYards] = useState(allYards);
const allTrucks = [{id: "1", name: "Truck 1"}, {id: "2", name: "Truck 2"}, {id: "3", name: "Truck 3"}]
const [trucks, setTrucks] = useState(allTrucks);
Render View code:
<View style={[styles.cardWrap, { padding: 30 }]}>
{assignTo === 'yard' ?
<>
<View style={[styles.inputGrp, { marginBottom: 30 }]}>
<Text style={[styles.inputLabel]}>Yard</Text>
<AutocompleteDropdown
ref={selectYardRef}
controller={(controller) => {
dropdownController.current = controller
}}
inputHeight={44}
debounce={600}
dataSet={yards.map((m) => ({
id: m.id,
title: m.name,
}))}
onChangeText={searchYards}
useFilter={false}
onSelectItem={(item) => {
console.log('selectedYard', item);
if (item?.id) {
setSelectedYard(item.id);
}
}}
textInputProps={{
placeholder: 'Choose the yard',
style: styles.autoInput,
}}
inputContainerStyle={styles.autoInputContainer}
containerStyle={{}}
rightButtonsContainerStyle={{
backgroundColor: '#fff',
}}
ClearIconComponent={<IconClear />}
ChevronIconComponent={<IconCaret />}
showChevron={true}
onClear={() => {
setSelectedYard(undefined);
}}
onFocus={handleOnFocus}
renderItem={(item, text) => (
<Text style={{ color: '#000', padding: 15 }}>
{`${item.title}`}
</Text>
)}
ItemSeparatorComponent={() => null}
/>
</View>
<View style={[styles.inputGrp]}>
<Text style={[styles.inputLabel]}>Address</Text>
<Text style={[styles.labelValue, { width: '50%' }]}>
123 Name Street
City, ST 00000
</Text>
</View>
</>
:
<View style={[styles.inputGrp, { marginBottom: 30 }]}>
<Text style={[styles.inputLabel]}>Truck</Text>
<AutocompleteDropdown
ref={selectTruckRef}
controller={(controller) => {
dropdownController.current = controller
}}
inputHeight={44}
debounce={600}
dataSet={trucks.map((m) => ({
id: m.id,
title: m.name,
}))}
onChangeText={searchTrucks}
useFilter={false}
onSelectItem={(item) => {
console.log('selectedYard', item);
if (item?.id) {
setSelectedTruck(item.id);
}
}}
textInputProps={{
placeholder: 'Choose the truck',
style: styles.autoInput,
}}
inputContainerStyle={styles.autoInputContainer}
containerStyle={{}}
rightButtonsContainerStyle={{
backgroundColor: '#fff',
}}
ClearIconComponent={<IconClear />}
ChevronIconComponent={<IconCaret />}
showChevron={true}
onClear={() => {
setSelectedTruck(undefined);
}}
onFocus={handleOnFocus}
renderItem={(item, text) => (
<Text style={{ color: '#000', padding: 15 }}>
{`${item.title}`}
</Text>
)}
ItemSeparatorComponent={() => null}
/>
</View>}
</View>
On change handler functions:
const searchTrucks = (searchText: string) => {
console.log("[~]Inside searchTrucks...");
if(searchText){
const regex = new RegExp(searchText, 'i');
const filteredTrucks = trucks.filter(truck => regex.test(truck.name));
setTrucks(filteredTrucks.slice(0, 5)); //Show only 1st 5 matches.
}
else{
setTrucks(allTrucks);
}
}
const searchYards = (searchText: string) => {
console.log("[~]Inside searchYards...");
if(searchText){
const regex = new RegExp(searchText, 'i');
const filteredYards = yards.filter(yard => regex.test(yard.name));
setYards(filteredYards.slice(0, 5)); //Show only 1st 5 matches.
}
else{
setYards(allYards);
}
}

Sticky header on SectionList ReactNative

I need to create a screen Catalog(Categories and Products).
I'm using SectionList from React Native in order to achive this.
I need to make that Categories component stick on the top when you scroll product lists.
Is there any library that could help me with this Catalog screen ?
Please look at the image here..
import React from "react";
import { View, StyleSheet, SectionList } from "react-native";
import Text from "../Text";
const DATA = [
{
title: "Main dishes",
data: ["Pizza", "Burger", "Risotto"],
},
{
title: "Sides",
data: ["French Fries", "Onion Rings", "Fried Shrimps"],
},
{
title: "Drinks",
data: ["Water", "Coke", "Beer"],
},
{
title: "Desserts",
data: ["Cheese Cake", "Ice Cream"],
},
];
const TabCategories = () => (
<View>
<Text>Horizontal list of categories</Text>
</View>
);
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const TestSectionList = (props) => {
return (
<View style={styles.container}>
<Text style={styles.SRC}>Some React Component</Text>
<SectionList
sections={DATA}
keyExtractor={(item, index) => item + index}
renderItem={({ item }) => <Item title={item} />}
renderSectionHeader={({ section: { title } }) => (
<Text style={styles.header}>{title}</Text>
)}
StickyHeaderComponent={TabCategories}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {},
SRC: {
fontWeight: "bold",
borderWidth: 1,
borderColor: "#fff",
padding: 10,
},
item: {
padding: 30,
},
header: {
fontWeight: "bold",
fontSize: 20,
},
});
export default TestSectionList;
stickySectionHeadersEnabled
Makes section headers stick to the top of the screen until the next one pushes it up
ListHeaderComponent
Rendered at the very beginning of the list
renderSectionHeader
Rendered at the top of each SECTION
I think this should do:
<SectionList
sections={DATA}
keyExtractor={(item, index) => item + index}
renderItem={({ item }) => <Item title={item} />}
ListHeaderComponent={({ section: { title } }) => (
<Text style={styles.header}>{title}</Text>
)}
renderSectionHeader={TabCategories}
stickySectionHeadersEnabled
/>
You can try this library react-native-tabs-section-list
https://github.com/bogoslavskiy/react-native-tabs-section-list
If you are talking about react-native-section-list, it inherits ScrollView props, you can check in the docs, in props section, so it has stickyHeaderComponent prop which should be exactly what you want.

Display custom image and link to a sectionList item on react native

I'm a newbie on react-native.
I want to build personalized data from array to populate sectionLists.
My actual code, extracted from react-native docs is
import React from "react";
import { StyleSheet, Text, View, SafeAreaView, SectionList, StatusBar } from "react-native";
const DATA = [
{
title: "Main dishes",
data: ["Pizza", "Burger", "Risotto"],
},
{
title: "Sides",
data: ["French Fries", "Onion Rings", "Fried Shrimps"]
},
{
title: "Drinks",
data: ["Water", "Coke", "Beer"]
},
{
title: "Desserts",
data: ["Cheese Cake", "Ice Cream"]
}
];
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const App = () => (
<SafeAreaView style={styles.container}>
<SectionList
sections={DATA}
keyExtractor={(item, index) => item + index}
renderItem={({ item }) => <Item title={item} />}
renderSectionHeader={({ section: { title } }) => (
<Text style={styles.header}>{title}</Text>
)}
/>
</SafeAreaView>
);
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: StatusBar.currentHeight,
marginHorizontal: 16
},
item: {
backgroundColor: "#f9c2ff",
padding: 20,
marginVertical: 8
},
header: {
fontSize: 32,
backgroundColor: "#fff"
},
title: {
fontSize: 24
}
});
export default App;
Here, we have only 2 dimensions to data array. I want to personalize that DATA array sending an image source, and a link to a screen on itemclick, for example.
I mean, I have actually title, data on DATA array. I want to add image and link columns to this DATA array and I want to have a solution to parse it in order to associate the link to props and display an image by its source content on image field.
Could you please tell me how to present that for the array and render it ?
Thanks.
EDIT :
I want to add 2 columns image and link on the DATA array like that :
const DATA = [
{
title: "Main dishes",
data: ["Pizza", "Burger", "Risotto"],
image: [require('../assets/Aquarium.png'), require('../assets/Aquarium.png'), require('../assets/Aquarium.png')]
link: ["Pizza", "Burger", "Risotto"]
},
{
title: "Sides",
data: ["French Fries", "Onion Rings", "Fried Shrimps"]
image: [require('../assets/Aquarium.png'), require('../assets/Aquarium.png'), require('../assets/Aquarium.png')]
link: ["FrenchFries", "OnionRings", "FriedShrimps"]
},
{
title: "Drinks",
data: ["Water", "Coke", "Beer"]
image: [require('../assets/Aquarium.png'), require('../assets/Aquarium.png'), require('../assets/Aquarium.png')],
link: ["Water", "Coke", "Beer"]
},
{
title: "Desserts",
data: ["Cheese Cake", "Ice Cream"]
image: [require('../assets/Aquarium.png'), require('../assets/Aquarium.png')]
link: ["CheeseCake", "IceCream"]
}
];
And I want to change my code like this to present image and link to a stackscreen name but it gives me errors.
return (
<SafeAreaView style={styles.container}>
<SectionList
sections={DATA}
keyExtractor={(item, index) => item + index}
renderItem={({ item }) =>
<TouchableWithoutFeedback
activeOpacity={0.4}
onPress={ () => navigation.navigate(item.link)}>
<View style={{flexDirection: 'row', textAlign: 'left', fontSize: 15, backgroundColor:'transparent', marginTop: 15, marginBottom: 15}}>
<Image source={item.image}/>
<Item title={item.title} />
</View>
</TouchableWithoutFeedback>
}
renderSectionHeader={({ section: { title } }) => (
<View>
<Text style={styles.header}>{title}</Text>
</View>
)}
/>
</SafeAreaView>
);
Could you please help me ?

React native cannot display flat list

I want to display the FlatList that I created. I want to show the title and artist that is in my data. There is no error but my output would not appear anything.
This is my data:
var track =
[
{ List: 'list1',
data:
[
{id: '1', url: 'http://tegos.kz/new/mp3_full/Luis_Fonsi_feat._Daddy_Yankee_-_Despacito.mp3',title: 'Despacito',artist:'Luis Fonsi'},
{id: '2', url: 'http://tegos.kz/new/mp3_full/5_Seconds_Of_Summer_-_Youngblood.mp3',title: 'YoungBlood',artist:'5SOS'},
]
},
{ List: 'list2',
data:
[
{id: '1111', url: 'http://tegos.kz/new/mp3_full/Yellow_Claw_and_San_Holo_-_Summertime.mp3',title: 'Summertime',artist:'Yelow Claw'},
{id: '2222', url: 'http://tegos.kz/new/mp3_full/Post_Malone_-_Better_Now.mp3',title: 'Better Now',artist:'Post Malone'},
]},
];
module.exports = {track:track};
And this is my FlatList:
export default class SongList extends Component{
render(){
const { navigate } = this.props.navigation;
return(
<View>
<FlatList
data={track}
renderItem={({item,index})=>{
return(
<FlatListItem item={item} index={index}>
</FlatListItem>);
}}
>
</FlatList>
</View>
);
}
}
class FlatListItem extends Component{
render(){
return(
<View style={styles.list}>
<View>
<Text style={styles.itemTitle}>{this.props.item.title}</Text>
<Text style={styles.itemArtist}>{this.props.item.artist}</Text>
</View>
</View>
);
}
}
Basically I am able to run the program. But there is nothing showing up on the screen. There is only a blank background.
const styles = StyleSheet.create({
itemArtist:{
textAlign: 'center',
justifyContent: 'center',
fontSize: 23,
borderBottomWidth: 4,
borderBottomColor: '#ccc',
marginTop: 10,
padding: 10,
color: 'blue',
},
itemTitle:{
textAlign: 'center',
justifyContent: 'center',
fontSize: 23,
borderBottomWidth: 4,
borderBottomColor: '#ccc',
marginTop: 10,
padding: 10,
color: 'blue',
},
list:{
flex:1,
}
You should write your code as below:
Your data:
export default [
{
List: 'list1',
data: [
{
id: '1',
url: 'http://tegos.kz/new/mp3_full/Luis_Fonsi_feat._Daddy_Yankee_-_Despacito.mp3',
title: 'Despacito',
artist: 'Luis Fonsi',
},
{
id: '2',
url: 'http://tegos.kz/new/mp3_full/5_Seconds_Of_Summer_-_Youngblood.mp3',
title: 'YoungBlood',
artist: '5SOS',
},
],
},
{
List: 'list2',
data: [
{
id: '1111',
url: 'http://tegos.kz/new/mp3_full/Yellow_Claw_and_San_Holo_-_Summertime.mp3',
title: 'Summertime',
artist: 'Yelow Claw',
},
{
id: '2222',
url: 'http://tegos.kz/new/mp3_full/Post_Malone_-_Better_Now.mp3',
title: 'Better Now',
artist: 'Post Malone',
},
],
},
];
Import your data like this, I assume the data file and your code are in a same folder:
import track from './data';
Your components:
export default class App extends Component {
render() {
const { navigate } = this.props.navigation;
return (
<View>
<FlatList
data={track}
renderItem={({ item, index }) => {
return <FlatListItem item={item} index={index} />;
}}
/>
</View>
);
}
}
class FlatListItem extends Component {
render() {
return (
<View style={styles.list}>
<View>
<Text style={styles.itemTitle}>{this.props.item.data[0].title}</Text>
<Text style={styles.itemArtist}>{this.props.item.data[0].artist}</Text>
</View>
<View>
<Text style={styles.itemTitle}>{this.props.item.data[1].title}</Text>
<Text style={styles.itemArtist}>{this.props.item.data[1].artist}</Text>
</View>
</View>
);
}
}
And if you want to show only the data of list1 in your FlatList you should change your code as below:
export default class App extends Component {
render() {
const { navigate } = this.props.navigation;
return (
<View>
<FlatList
data={track[0].data}
renderItem={({ item, index }) => {
return <FlatListItem item={item} index={index} />;
}}
/>
</View>
);
}
}
class FlatListItem extends Component {
render() {
return (
<View style={styles.list}>
<View>
<Text style={styles.itemTitle}>{this.props.item.title}</Text>
<Text style={styles.itemArtist}>{this.props.item.artist}</Text>
</View>
</View>
);
}
}
You can make your data schema better to show them better too.
Steps to debug :-
try to console track, check if data is coming properly.
add console in componentDidMount and check if item if coming there or not.
Add keyExtractor in flatlist, keyExtractor tells the list to use the ids for the react keys instead of the default key property.
<FlatList
data={track}
keyExtractor={(item, index) => ""+index}
renderItem={({ item, index }) => {
return <FlatListItem item={item} index={index} />;
}}
/>