JSX element doesn't render inside a loop - reactjs

I have an array of stock data for my shopping store which I would like to render in the screen with the help of a for loop. But only the first item in the array is being rendered, while the array have 9 items.
I also have tried putting the render function outside the functional component, still the same issue.
Plz help me to identify the problem. Thanks.
code
const Home = () => {
const [isSneakersActive, setIsSneakersActive] = React.useState(false);
const [isWatchActive, setIsWatchActive] = React.useState(false);
const [isBackpackActive, setIsBackpackActive] = React.useState(false);
const screenWidth = Dimensions.get('window').width;
const renderProducts = () => {
for (let i = 0; i < Products.length; i++) {
const element = Products[i];
return (
<ProductCard>
<ProductHeader>
{element.discount === 'none' ? (
<DiscountLabel style={{backgroundColor: '#fff'}} />
) : (
<DiscountLabel>
<Text size={13} weight="bold">
{element.discount}
</Text>
</DiscountLabel>
)}
{element.favourite === 'yes' ? (
<Ionicons name="heart-circle" color="#F75058" size={20} />
) : (
<AntDesign name="heart" color="#B6B8C7" size={15} />
)}
</ProductHeader>
<ProductPicture>
<View style={ProductPictureStyles.border}>
<View style={ProductPictureStyles.circle}>
<Image
source={element.imageSrc}
style={[
ProductPictureStyles.image,
{
height: (screenWidth / 1731) * 433,
},
]}
/>
</View>
</View>
</ProductPicture>
<ProductName>
<Text color="#3D44AA" size={(screenWidth / 380) * 18} weight="bold">
{element.name}
</Text>
</ProductName>
<ProductPrice>
<Text color="#3D44AA" size={(screenWidth / 380) * 18} weight="bold">
{element.price}
</Text>
</ProductPrice>
<ProductRating>
<AntDesign name="star" color="#fdd344" size={18} />
<AntDesign name="star" color="#fdd344" size={18} />
<AntDesign name="star" color="#fdd344" size={18} />
<AntDesign name="star" color="#fdd344" size={18} />
<AntDesign name="staro" color="#f0e8c9" size={18} />
</ProductRating>
</ProductCard>
);
}
};
return (
<View style={{flex: 1}}>
<Section5 style={{paddingHorizontal: 0}}>
<ScrollView showsVerticalScrollIndicator={false}>
{isSneakersActive ? (
<Section5 style={{paddingHorizontal: 0}}></Section5>
) : isWatchActive ? (
<Section5 style={{paddingHorizontal: 0}}></Section5>
) : isBackpackActive ? (
<Section5 style={{paddingHorizontal: 0}}></Section5>
) : (
<Section5 style={{paddingHorizontal: 0}}>
{renderProducts()}
</Section5>
)}
</ScrollView>
</Section5>
</View>
);
};
export default Home;
stock data
export const Products = [
{
id: 1,
category: 'shoe',
name: 'Air Max Motion',
imageSrc: require('../images/sneekers.png'),
price: '$ 250',
rating: 5,
discount: '8%',
favourite: 'yes',
},
{
id: 2,
category: 'backpack',
name: 'Hiking Starlet',
imageSrc: require('../images/backpack.png'),
price: '$ 350',
rating: 5,
discount: '5%',
favourite: 'yes',
},
{
id: 3,
category: 'backpack',
name: 'Hand Bag',
imageSrc: require('../images/backpack02.png'),
price: '$ 80',
rating: 3.5,
discount: '8%',
favourite: 'no',
},
{
id: 4,
category: 'shoe',
name: 'Nike Air Max',
imageSrc: require('../images/sneekers02.png'),
price: '$ 240',
rating: 4,
discount: 'none',
favourite: 'no',
},
{
id: 5,
category: 'watch',
name: 'Royal Rolex',
imageSrc: require('../images/watch.png'),
price: '$ 50',
rating: 5,
discount: 'none',
favourite: 'no',
},
{
id: 6,
category: 'shoe',
name: 'Hiker Max',
imageSrc: require('../images/sneekers03.png'),
price: '$ 180',
rating: 4.5,
discount: 'none',
favourite: 'no',
},
{
id: 7,
category: 'backpack',
name: 'School Bag',
imageSrc: require('../images/backpack01.png'),
price: '$ 120',
rating: 3.5,
discount: '10%',
favourite: 'no',
},
{
id: 8,
category: 'watch',
name: 'Silver Liner',
imageSrc: require('../images/watch01.png'),
price: '$ 35',
rating: 4.5,
discount: '22%',
favourite: 'yes',
},
{
id: 9,
category: 'shoe',
name: 'Leather Sneaker',
imageSrc: require('../images/sneekers01.png'),
price: '$ 200',
rating: 4,
discount: 'none',
favourite: 'no',
},
];

The problem is that your are looping the array but returning just the first element.
the correct way to do it is via map
const renderProducts = () => {
for (let i = 0; i < Products.length; i++) {
const element = Products[i];
return ( //return just the first
<ProductCard>
...
</ProductCard>
);
}
};
const renderProducts = () => products.map((element, i) => {
return (
<ProductCard key={i}>
...
</ProductCard>
);
};

Related

render MUI components from an array of data and display the first one differently

Here I am trying to render the contents of Accordion through a list array passing down the props to a component. I kind of understand where the issue is but I don't know how else I can call the component and pass the props. Below is my code.
Code of the parent component
const Sandbox = () => {
let summaryContents: any[] = [
{
Title: "Construction costs",
TotalPrice: "$25000",
Subcontents: [
{
Subtitle: "Sanitation",
SubtitlePrice: "$5000",
},
{
Subtitle: "PoolLights",
SubtitlePrice: "$5000",
},
{
Subtitle: "PoolCleaner",
SubtitlePrice: "$15000",
},
],
},
{
Title: "Pool interior costs",
TotalPrice: "$20000",
Subcontents: [
{
Subtitle: "Title1",
SubtitlePrice: "$5000",
},
{
Subtitle: "Title2",
SubtitlePrice: "$10000",
},
{
Subtitle: "Title3",
SubtitlePrice: "$5000",
},
],
},
];
let summaryContentsList: any[] = [];
summaryContents.forEach((item: any, index: number) => {
summaryContentsList.push(
<QuoteSummary
Title={item.Title}
TotalPrice={item.TotalPrice}
Subtitle={item.Subcontents.Subtitle}
SubtitlePrice={item.Subcontents.SubtitlePrice}
/>
);
});
return (
<>
{summaryContentsList}
</>
);
};
Code for the child component
const QuoteSummary: FC<QuoteSummaryProps> = (props: QuoteSummaryProps) => {
const classes = useStyles();
return (
<QuoteCard>
<Typography variant="h1" sx={{ paddingBottom: 2 }}>
Quote Summary
</Typography>
<DialogCloseButton onClose={clicked} />
<Accordion
className={classes.accordion}
sx={{
paddingTop: 0,
}}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Typography variant="h3">{props.Title}</Typography>
<Typography variant="h3" sx={{ paddingLeft: 10 }}>
{props.TotalPrice}
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>{props.Subtitle}</Typography>
<Typography>{props.SubtitlePrice}</Typography>
</AccordionDetails>
</Accordion>
</QuoteCard>
);
};
This is how it looks where as I wanted to render the Title only once and accordion contents below.
What would be the approach I will have to follow
You can put the QuoteCard outside and only place Accordion item in the child component:
const QuoteSummary: FC<QuoteSummaryProps> = (props: QuoteSummaryProps) => {
return (
<Accordion>
{...}
</Accordion>
);
};
<QuoteCard>
<Typography variant="h6" sx={{ paddingBottom: 2 }}>
Quote Summary
</Typography>
<DialogCloseButton onClose={() => {}} />
{summaryContents.map((item) => (
<QuoteSummary
Title={item.Title}
TotalPrice={item.TotalPrice}
Subtitle={item.Subcontents.Subtitle}
SubtitlePrice={item.Subcontents.SubtitlePrice}
/>
))}
</QuoteCard>
EDIT: Another approach is to render the title conditionally in the child component based on the props provided from the parent:
const QuoteSummary: FC<QuoteSummaryProps> = (props: QuoteSummaryProps) => {
return (
<QuoteCard>
{props.displayTitle && (
<Typography variant="h6" sx={{ paddingBottom: 2 }}>
Quote Summary
</Typography>
)}
<DialogCloseButton onClose={() => {}} />
<Accordion>
{...}
</Accordion>
</QuoteCard>
);
};
<>
{summaryContents.map((item, i) => (
<QuoteSummary
displayTitle={i === 0}
Title={item.Title}
TotalPrice={item.TotalPrice}
Subtitle={item.Subcontents.Subtitle}
SubtitlePrice={item.Subcontents.SubtitlePrice}
/>
))}
</>
You can create a render function for array items and use them like this:
const Sandbox = () => {
const summaryContents: any[] = [
{
Title: "Construction costs",
TotalPrice: "$25000",
Subcontents: [{
Subtitle: "Sanitation",
SubtitlePrice: "$5000",
},
{
Subtitle: "PoolLights",
SubtitlePrice: "$5000",
},
{
Subtitle: "PoolCleaner",
SubtitlePrice: "$15000",
},
],
},
{
Title: "Pool interior costs",
TotalPrice: "$20000",
Subcontents: [{
Subtitle: "Title1",
SubtitlePrice: "$5000",
},
{
Subtitle: "Title2",
SubtitlePrice: "$10000",
},
{
Subtitle: "Title3",
SubtitlePrice: "$5000",
},
],
},
];
const renderContent = (item: any) => (
<QuoteSummary
Title={item.Title}
TotalPrice={item.TotalPrice}
Subtitle={item.Subcontents.Subtitle}
SubtitlePrice={item.Subcontents.SubtitlePrice}
/>
);
return (
<>
{summaryContents.map(renderContent)}
</>
);
};

React Ant deisgn 4 Table search input cursor going to center

Im using my react project for ant design 4 table, when I search the table data , input cursor going to center and data not searching any solution for this, please look ta my following link and just copy paste address then search you can see the conflict.
stakblitz
code here
const data = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
},
{
key: '2',
name: 'Joe Black',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Jim Green',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
{
key: '4',
name: 'Jim Red',
age: 32,
address: 'London No. 2 Lake Park',
},
];
class App extends React.Component {
state = {
searchText: '',
searchedColumn: '',
};
getColumnSearchProps = dataIndex => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}>
<Input
ref={node => {
this.searchInput = node;
}}
placeholder={`Search ${dataIndex}`}
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
style={{ width: 188, marginBottom: 8, display: 'block' }}
/>
<Space>
<Button
type="primary"
onClick={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
Search
</Button>
<Button onClick={() => this.handleReset(clearFilters)} size="small" style={{ width: 90 }}>
Reset
</Button>
</Space>
</div>
),
filterIcon: filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />,
onFilter: (value, record) =>
record[dataIndex]
? record[dataIndex].toString().toLowerCase().includes(value.toLowerCase())
: '',
onFilterDropdownVisibleChange: visible => {
if (visible) {
setTimeout(() => this.searchInput.select(), 100);
}
},
render: text =>
this.state.searchedColumn === dataIndex ? (
<Highlighter
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
searchWords={[this.state.searchText]}
autoEscape
textToHighlight={text ? text.toString() : ''}
/>
) : (
text
),
});
handleSearch = (selectedKeys, confirm, dataIndex) => {
confirm();
this.setState({
searchText: selectedKeys[0],
searchedColumn: dataIndex,
});
};
handleReset = clearFilters => {
clearFilters();
this.setState({ searchText: '' });
};
render() {
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
width: '30%',
...this.getColumnSearchProps('name'),
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
width: '20%',
...this.getColumnSearchProps('age'),
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
...this.getColumnSearchProps('address'),
},
];
return <Table columns={columns} dataSource={data} />;
}
}

How to render items in react native FlatList with 2 columns when some of them must be full width

I want to render product list in React Native with 2 columns by default, but if any item is a special product, then make it full width.
const data = [
{id: '1', name: 'Item1', price: 25, special_product: false},
{id: '2', name: 'Item2', price: 15, special_product: false},
{id: '3', name: 'Item3', price: 11, special_product: true},
{id: '4', name: 'Item4', price: 22, special_product: false},
{id: '5', name: 'Item5', price: 32, special_product: false},
{id: '6', name: 'Item6', price: 22, special_product: false},
{id: '7', name: 'Item7', price: 22, special_product: false},
]
And I want to get FlatList structure like this:
[Item 1][Item2]
[Special Item3]
[Item4] [Item5]
[Item6] [Item7]
My code is really simple now:
<FlatList
ref={(ref) => { this.flatListRef = ref; }}
contentContainerStyle={{ flexGrow: 1 }}
horizontal={false}
data={data}
keyExtractor={({ id }) => id}
onRefresh={this.onListRefresh}
refreshing={refreshing}
renderItem={this.renderItems}
ListHeaderComponent={this.renderHeader}
ListEmptyComponent={this.renderEmptyList.bind(this, data, use)}
/>
My item container styles looks like this:
const Styles = StyleSheet.create({
container: {
flex: 0.5,
margin: Layout.Margin.Narrow,
shadowColor: ShadowColor.Standard,
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.5,
shadowRadius: 4,
elevation: 5,
borderBottomLeftRadius: 5,
borderBottomRightRadius: 5,
},
...
});
Item that is rendered by renderItem function:
// Item
...
return (
<TouchableWithoutFeedback
onPress={() => console.log('user clicked on the item')}>
<View style={{
...itemStyle.container
}}
<StyledText
type={"small"}
numberOfLines={1}
allowFontScaling={false}
style={itemStyle.centerText}>
{name}
</StyledText>
</View>
</TouchableWithoutFeedback>
How can I do this? I'm using React Native v0.60.5
You can use the number of columns prop and provide a width of 100% this will give the output you need.
This is a working sample you can apply it your item styles in anyway you need.
Flatlist code
<FlatList
numColumns={2}
data={data}
renderItem={({ item }) => (
<Item
id={item.id}
title={item.name}
selected={item.special_product}
/>
)}
keyExtractor={(item) => item.id}
/>
Render item function
function Item({ id, title, selected }) {
return (
<TouchableOpacity
onPress={() => {}}
style={[
selected ? { width: '100%' } : { width: '50%' },
{ backgroundColor: selected ? '#6e3b6e' : '#f9c2ff' },
]}>
<Text style={{}}>{title}</Text>
</TouchableOpacity>
);
}
As you can see I've set the width conditionally based the selected flag.

Recharts - bar chart dynamic label position

How can I have dynamic label positions of Bars like is showing in the picture?
Here is my code till now
const data = [
{ currency: 'CHF', amount: 3, amountLabel: 3023.00 },
{ currency: 'GBP', amount: 6, amountLabel: 6275.00 },
{ currency: 'USD', amount: 10, amountLabel: 9999.00 },
{ currency: 'EUR', amount: 14, amountLabel: 14819.00 },
{ currency: 'LEK', amount: 24, amountLabel: 24023000.00 },
];
<BarChart
width={430}
height={170}
data={data}
layout="vertical">
<XAxis type="number" orientation="top" stroke="#285A64" />
<YAxis type="category" dataKey="currency" axisLine={false} dx={-5} tickLine={false}
style={{ fill: "#285A64" }} />
<Bar background dataKey="amount" fill="#285A64" barSize={{ height: 26 }}>
<LabelList dataKey="amountLabel" position="insideRight" style={{ fill: "white" }} />
</Bar>
</BarChart>
Find Sample code here jsfiddle
You should implement a React component to be injected into the prop content (LabelList)
For example (JSFiddle):
const {BarChart, Bar, XAxis, YAxis, LabelList} = Recharts;
const data = [
{ currency: 'CHF', amount: 3, amountLabel: 3023.00 },
{ currency: 'GBP', amount: 6, amountLabel: 6275.00 },
{ currency: 'USD', amount: 10, amountLabel: 9999.00 },
{ currency: 'EUR', amount: 14, amountLabel: 14819.00 },
{ currency: 'LEK', amount: 26, amountLabel: 26023000.00 },
];
const renderCustomizedLabel = (props) => {
const {
x, y, width, height, value,
} = props;
const fireOffset = value.toString().length < 5;
const offset = fireOffset ? -40 : 5;
return (
<text x={x + width -offset} y={y + height - 5} fill={fireOffset ? "#285A64" :"#fff"} textAnchor="end">
{value}
</text>
);
};
const VerticalBarChart = React.createClass({
render () {
return (
<BarChart
width={400}
height={170}
data={data}
layout="vertical">
<XAxis type="number" orientation="top" stroke="#285A64"/>
<YAxis type="category" dataKey="currency" axisLine={false} dx={-10} tickLine={false} style={{ fill: "#285A64" }} />
<Bar background dataKey="amount" fill="#285A64" barSize={{ height: 26 }}>
<LabelList dataKey="amountLabel" content={renderCustomizedLabel} position="insideRight" style={{ fill: "white" }} />
</Bar>
</BarChart>
);
}
})
ReactDOM.render(
<VerticalBarChart />,
document.getElementById('container')
);

Fetch data from firebase realtime database, React Native (expo)

I have that code, I need to fetch data instead of the static array here.
Note: have connected to firebase realtime database and all that stuff, I just need to fetch data and map them, I will need to render them in a list.
const rec = [
{
name: 'Brothers Restaurant',
avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/ladylexy/128.jpg',
address: 'Address St. Random Number',
link: 'Home'
},
{
name: 'Example Restaurant',
avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/adhamdannaway/128.jpg',
address: 'Address St. Random Number 23',
link: 'About'
},
{
name: 'Example Restaurant',
avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/adhamdannaway/128.jpg',
address: 'Address St. Random Number 23',
link: 'About'
},
{
name: 'Example Restaurant',
avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/adhamdannaway/128.jpg',
address: 'Address St. Random Number 23',
link: 'About'
},
]
const discover = [
{
name: 'Discover Restaurant',
avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/ladylexy/128.jpg',
address: 'Address St. Random Number',
link: 'Home'
},
{
name: 'Example Discover Restaurant',
avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/adhamdannaway/128.jpg',
address: 'Address St. Random Number 23',
link: 'About'
},
{
name: 'Discover Restaurant',
avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/ladylexy/128.jpg',
address: 'Address St. Random Number',
link: 'Home'
},
{
name: 'Example Discover Restaurant',
avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/adhamdannaway/128.jpg',
address: 'Address St. Random Number 23',
link: 'About'
},
{
name: 'Discover Restaurant',
avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/ladylexy/128.jpg',
address: 'Address St. Random Number',
link: 'Home'
},
{
name: 'Example Discover Restaurant',
avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/adhamdannaway/128.jpg',
address: 'Address St. Random Number 23',
link: 'About'
},
]
export default class RestaurantScreen extends Component {
static navigationOptions = {
title: 'Restaurants',
headerStyle: {
backgroundColor: '#c4463d',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}
render() {
return (
<View style={styles.container}>
<Text style={{ fontSize: 24, fontWeight: '700', color: '#c4463d' }}>Recommendations</Text>
<ScrollView
style={styles.categories}>
<View>
{
rec.map((l, i) => (
<ListItem
key={i}
leftAvatar={{ source: { uri: l.avatar_url } }}
title={l.name}
address={l.subtitle}
onPress={() => this.props.navigation.navigate(`${l.link}`)}
bottomDivider
/>
))
}
</View>
</ScrollView>
<View style={styles.recommendations}>
<Text style={{ fontSize: 24, fontWeight: '700', color: '#c4463d' }}>Discover</Text>
<ScrollView>
{
discover.map((l, i) => (
<ListItem
key={i}
leftAvatar={{ source: { uri: l.avatar_url } }}
title={l.name}
address={l.subtitle}
bottomDivider
/>
))
}
</ScrollView>
</View>
</View>
)
}
}
official documentation from expo didn't help a lot to be honest ^^ and I can't get this thing posted because I have a lot of code in here? -.-
Basically if everything is set up, you just need to put listener at lifecycle method (componentDidMount) and set the data inside state.
for more info, you can check firebase js sdk
https://firebase.google.com/docs/web/setup
export default class RestaurantScreen extends Component {
state = {
rec: [],
discover: []
}
static navigationOptions = {
title: 'Restaurants',
headerStyle: {
backgroundColor: '#c4463d',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}
componentDidMount() {
firebase.database().ref('places').on('value', (snapshot) => {
const rec = snapshot.val();
this.setState({ rec, discover: rec })
});
}
render() {
const { rec, discover } = this.state;
return (
<View style={styles.container}>
<Text style={{ fontSize: 24, fontWeight: '700', color: '#c4463d' }}>Recommendations</Text>
<ScrollView
style={styles.categories}>
<View>
{
rec.map((l, i) => (
<ListItem
key={i}
leftAvatar={{ source: { uri: l.avatar_url } }}
title={l.name}
address={l.subtitle}
onPress={() => this.props.navigation.navigate(`${l.link}`)}
bottomDivider
/>
))
}
</View>
</ScrollView>
<View style={styles.recommendations}>
<Text style={{ fontSize: 24, fontWeight: '700', color: '#c4463d' }}>Discover</Text>
<ScrollView>
{
discover.map((l, i) => (
<ListItem
key={i}
leftAvatar={{ source: { uri: l.avatar_url } }}
title={l.name}
address={l.subtitle}
bottomDivider
/>
))
}
</ScrollView>
</View>
</View>
)
}
}

Resources