Why are my React Native View heights inconsistent? - react-native

I have the following code:
return (
<>
<View style={styles.dashboardListItemContainer}>
<View style={styles.listItemBorder} />
</View >
</>
)
const styles = StyleSheet.create({
dashboardListItemContainer: {
minHeight: 73,
backgroundColor: COL_DARK_BG,
display: "flex",
flexDirection: "column",
},
listItemBorder: {
minHeight: 0.5,
backgroundColor: 'white',
}
});
Which produces the following result:
My question is, why are the lines inconsistently bright / appear to be different heights?
Also when I change column to row here: flexDirection: "row", the line disappears completely. I can't tell if this is a bug or there are errors in my code?
TIA.
Update:
I cannot solve this problem on any device, and I've tried different methods for determining the height.
borderBottomWidth: StyleSheet.hairlineWidth, looks like this:
You can see in the above picture some lines do not even show up.
borderBottomWidth: StyleSheet.hairlineWidth * 2, looks like this:
And height: 0.5, looks like this on a white background:
The problem is consistent across devices, it is at the edge of an item in a <FlatList>.

Android Emulator has less resolution, try on a real device, sometimes i have the same error, and when I run on a real device it looks good.

We can use flex value.
import React, { Component } from "react";
import { View, FlatList } from "react-native";
import { StyleSheet } from "react-native";
class App extends Component {
render() {
return (
<FlatList
data={[1, 2, 3, 4, 5, 6, 7, 8, 9]}
extraData={[1, 2, 3, 4, 5, 6, 7, 8, 9]}
horizontal={false}
renderItem={({ item, index }) => {
return (
<View style={styles.dashboardListItemContainer}>
<View style={styles.listItemBorder} />
</View>
);
}}
key={({ item, index }) => index}
/>
);
}
}
export default App;
const styles = StyleSheet.create({
dashboardListItemContainer: {
backgroundColor: "red",
display: "flex",
flex: 1,
minHeight: 73,
flexDirection: "column"
},
listItemBorder: {
minHeight: 0.5,
backgroundColor: "yellow"
}
});

Related

React Native: Warning: Each child in a list should have a unique "key" prop

I'm quite new to React Native and have a question.
I get this warning: Each child in a list should have a unique "key" prop.
I've tried everything. Now I even have Math.random() as key and I still get the warning.
Home.js:
return(
<ScrollView style={styles.container}>
<StatusBar barStyle='light-content' />
<ImageBackground source={image} style={styles.image} imageStyle={styles.image2}>
<LinearGradient colors={['transparent', 'rgba(249,249,249,1)' ]} locations={[.4, 1]}
style={{
position: 'absolute',
left: 0,
right: 0,
top: 0,
height: 400
}} />
<TouchableOpacity activeOpacity={0.9} style={styles.topNews} onPress={()=> navigation.navigate('WebView')}>
<Text style={styles.topCategoryText}>ITALIAN LEAGUE</Text>
<Text style={styles.topTitleText}>Juventus legend: Ronaldo is natural to be criticized</Text>
<Text style={styles.topSourceText}>CNN Sport</Text>
</TouchableOpacity>
</ImageBackground>
<View style={{marginHorizontal: 10, flex: 1}}><RNMasonryScrollView
colums='2'
columnStyle={{flexDirection: 'column'}}
oddColumnStyle={{flex: 1, marginRight:15, marginLeft:10}}
evenColumnStyle={{flex:1,marginLeft:15}}
>
{[
<NewsDetail Key='1' title="Papers: Salah eager for Barca move" category='LA LIGA' imageSrc='https://en.as.com/en/imagenes/2020/06/11/football/1591881357_315795_noticia_normal.jpg'/>,
<NewsDetail Key='2' title="Man Utd struggles 'mentally impacting' Pogba, says France boss Deschamps" category='PREMIER LEAGUE' imageSrc='https://resources.premierleague.com/premierleague/photo/2019/06/20/88784d96-ef4b-4414-8b59-517c15b162a5/MW1-EditorialLead-new.png'/>,
<NewsDetail Key='3' title="Arsenal's complete player: The meteoric rise of Vivianne Miedema" category='PREMIER LEAGUE' imageSrc='https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcTupBTx2is9w3Z7pIhrorpPDMTFHmQhS1Ypmg&usqp=CAU'/>,
<NewsDetail Key='4' title="Mourinho hit with suspension by UEFA" category='SERIE A' imageSrc='https://www.telegraph.co.uk/content/dam/football/2018/02/13/TELEMMGLPICT000153853426_trans_NvBQzQNjv4BqwD2sfO9joeQ6RY-qlTATNB2cSHopZMn-aCc647VHTAY.jpeg'/>,
<NewsDetail Key='5' title="'Ronaldo is definitely faster than me!' – Bolt" category='LA LIGA' imageSrc='https://resources.premierleague.com/premierleague/photo/2018/08/10/bf1acdf0-7b10-4dfe-8844-06f0f18d5c38/2018-08-10T192712Z_1257041591_RC18CE142CA0_RTRMADP_3_SOCCER-ENGLAND-MUN-LEI.JPG'/>,
<NewsDetail Key='6' title="Southgate admits to fears over Maguire's career" category='LIGUE 1' imageSrc='https://images.daznservices.com/di/library/GOAL/a8/c9/vivianne-miedema-goal-50-gfx_nuhcgkr4tthu1kyux2ymq4y4l.jpg?t=-1147520971&quality=60&w=1200'/>,
]}
</RNMasonryScrollView></View>
</ScrollView>
)
NewsDetail.js
import React, {useState, useEffect} from 'react';
import {View, Text, StyleSheet, Image, Dimensions } from 'react-native';
const NewsDetail = (props) => {
const random = Math.random()
const ViewWidth = 157.5
// const [imageSize, setImageSize] = useState({width: 0, height: 0});
// const [viewSize, setViewSize] = useState({width: 0, height: 0});
const [imageHeight, setHeight] = useState(0);
const myUri = props.imageSrc;
useEffect(() => {
Image.getSize(myUri, (width, height) => {
setHeight(height / (width / ViewWidth));
});
}, [])
if(imageHeight > 0){
console.log(random)
return (
<View style={styles.newsDetail} key={`${random}`}>
<Image
resizeMode='cover'
style={{
width: ViewWidth,
height: imageHeight,
borderTopLeftRadius: 7,
borderTopRightRadius: 7,
}}
source={{ uri: myUri,}}
/>
<Text style={styles.textOne}>{props.category}</Text>
<Text style={styles.textTwo}>{props.title}</Text>
</View>)
} else return null;
}
const styles = StyleSheet.create({
image:{
width: '100%',
borderTopLeftRadius: 7,
borderTopRightRadius: 7
},
newsDetail:{
backgroundColor: "white",
marginTop: 10,
borderRadius: 7,
opacity: 0.9,
shadowColor: "grey",
shadowRadius: 5,
shadowOffset: {width: 0, height: 0},
shadowOpacity: 0.3
},
textOne:{
fontSize: 10,
color: '#7A7F82',
fontWeight: 'bold',
paddingTop: 10,
paddingHorizontal: 10,
paddingBottom:3
},
textTwo:{
fontSize: 14,
color: '#2D3041',
fontWeight: 'bold',
paddingHorizontal: 10,
paddingBottom:10
}
});
export default NewsDetail;
I dont know what to do. Any help? Also, is there any websites where I can pay to get quick help on questions I have about React Native? Similar to StackOverflow just you pay to get quick answers on all questions?
A proper way to generate a list is to create an array of objects, then you use map to display. In your codes, it's almost correct. You should use key instead of Key.
const articles = [
{ id: 1, title: "Papers: Salah eager for Barca move", category: 'LA LIGA', imageSrc: 'https://en.as.com/en/imagenes/2020/06/11/football/1591881357_315795_noticia_normal.jpg' },
{id: '2', title: "Man Utd struggles 'mentally impacting' Pogba, says France boss Deschamps", category: 'PREMIER LEAGUE', imageSrc: 'https://resources.premierleague.com/premierleague/photo/2019/06/20/88784d96-ef4b-4414-8b59-517c15b162a5/MW1-EditorialLead-new.png'},
{ id:'3',title: "Arsenal's complete player: The meteoric rise of Vivianne Miedema", category: 'PREMIER LEAGUE', imageSrc: 'https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcTupBTx2is9w3Z7pIhrorpPDMTFHmQhS1Ypmg&usqp=CAU'}]
<RNMasonryScrollView
colums='2'
columnStyle={{flexDirection: 'column'}}
oddColumnStyle={{flex: 1, marginRight:15, marginLeft:10}}
evenColumnStyle={{flex:1,marginLeft:15}}
>
{ articles.map((article) => {
return <NewsDetail key={article.id} title={article.title} imageSrc={article.imageSrc} />
})}
</RNMasonryScrollView>

get rid of border in Card Component React native element

In the Card Component for react native elements
I'm trying to get rid of the border by setting the border to 0 and borderColor to transparent but there's still a gray outline
<Card
containerStyle={{borderWidth: 0, borderColor: 'transparent', elevation: 0}}
title='HELLO WORLD'
image={require('../images/pic2.jpg')}>
<Text style={{marginBottom: 10}}>
The idea with React Native Elements is more about component structure than actual design.
</Text>
</Card>
Thought it might have been box shadow, but that's not it either
I've got the same issue, and I've found that border appears because the Card element has an elevation default setted to 1
You can override this (for android) :
<Card containerStyle={{elevation:0, backgroundColor:#123}}/>
and in IOS:
const styles = {
container: {
shadowColor: 'rgba(0,0,0, .2)',
shadowOffset: { height: 0, width: 0 },
shadowOpacity: 0, //default is 1
shadowRadius: 0//default is 1
}
}
<Card containerStyle={styles.container} />
Its late but it seems that a lot of people still searching for the Answer.
React Native Elements by default have set both borderWidth and shadow Props, so in order to remove border completely you need to remove both Border and Shadow.
<Card containerStyle={styles.cardCnt}>
<Text>Content</Text>
</Card>
const styles = {
cardCnt: {
borderWidth: 0, // Remove Border
shadowColor: 'rgba(0,0,0, 0.0)', // Remove Shadow for iOS
shadowOffset: { height: 0, width: 0 },
shadowOpacity: 0,
shadowRadius: 0,
elevation: 0 // Remove Shadow for Android
}
};
It looks like react native elements' Card component has a grey border in all of the examples I've seen. I'd suggest building your own card component. Start with something like this and then style it however you want. This one has a bit of shadow which you can turn off by passing it a noShadow prop.
import React from 'react';
import { View, StyleSheet } from 'react-native';
const Card = (props) => {
let shadowStyle = {
shadowColor: COLORS.grey3,
shadowOffset: { width: 0, height: 0 },
shadowOpacity: .5,
shadowRadius: 12,
elevation: 1,
}
if (props.noShadow) {
shadowStyle = {}
}
return (
<View style={[styles.containerStyle, props.style, shadowStyle]}>
{props.children}
</View>
);
};
const styles = StyleSheet.create({
containerStyle: {
padding: 10,
marginHorizontal: 10,
backgroundColor: COLORS.white,
borderRadius: 3,
}
})
export { Card };
Then when you want to use it just
import { Card } from './yourCustomCardFile'
Then in your render method
<Card>
<Text>Any content you want to include on the card</Text>
<Text>More content that you want on the card</Text>
</Card>
set elevation to 0 and borderColor to white like this
<Card containerStyle={{ elevation: 0, borderColor: "white" }}>
set to screen background color
Dirty but problem solved.

React Native FlatList rendering a few items at a time

I have a list of chat messages in my app to which new items are added to the bottom. I used some code from another SO question to make the FlatList stick to the bottom when new items are added, as below
<FlatList
data={messages}
renderItem={({item}) => <ChatMessage message={item}></ChatMessage>}
keyExtractor={(item, index) => index.toString()}
initialNumToRender={messages.length}
initialScrollIndex={messages.length-1}
ref={ref => this.flatList = ref}
onContentSizeChange={(contentWidth, contentHeight)=>{
this.flatList.scrollToEnd();
}}
/>
The problem is that when the initial list renders (only 35 items, hardcoded in an array for now) it seems to render just a few items, then scroll down a bit, then render a few more, then scroll down a bit until it finally completes the rendering and sticks to the bottom. It's choppy and slow, despite adding initialNumToRender={messages.length} and rendering an incredibly simple node for each result.
Ideally I guess I need to wait for it to fully render before displaying anything to the user but (A) they'd have to wait a couple of seconds to start using the chat room and (B) I don't think that's how Flatlist works, I assume the elements have to be viewable before it is rendered.
Is there just a better way to do this? (Testing on Android by the way)
EDIT: Adding ChatMessage component for completeness
// Chat Message
import React, { Component } from 'react'
import {
StyleSheet,
ImageBackground,
Text,
View
} from 'react-native'
class ChatMessage extends Component {
constructor(props) {
super(props)
this.state = { }
}
render() {
return (
<View style={styles.chatMessage}>
<View style={styles.chatMessage_layout}>
<View style={styles.chatMessage_pic}>
<View style={styles.chatMessage_pic_image}>
<ImageBackground
source={require('./assets/images/profile-pics/example-profilr.png')}
style={styles.chatMessage_pic_image_background}
imageStyle={{ borderRadius: 40/2 }}
resizeMode="cover"
>
</ImageBackground>
</View>
</View>
<View style={styles.chatMessage_details}>
<View style={styles.chatMessage_name}>
<Text style={styles.chatMessage_name_text}>
{this.props.message.name}
<Text style={styles.chatMessage_name_time}> 24h</Text>
</Text>
</View>
<View style={styles.chatMessage_message}>
<Text style={styles.chatMessage_message_text}>{this.props.message.text}</Text>
</View>
</View>
</View>
</View>
)
}
}
export default ChatMessage;
const styles = StyleSheet.create({
chatMessage: {
paddingVertical: 10,
paddingHorizontal: 24
},
chatMessage_layout: {
flexDirection: 'row'
},
chatMessage_pic: {
width: 40,
height: 40,
marginRight: 12
},
chatMessage_pic_image: {
width: 40,
height: 40
},
chatMessage_pic_image_background: {
width: 40,
height: 40
},
chatMessage_details: {
flex: 1
},
chatMessage_name_text: {
color: '#FFF',
fontSize: 14,
fontWeight: 'bold'
},
chatMessage_name_time: {
fontSize: 11,
color: 'rgba(255,255,255,0.6)'
},
chatMessage_message: {
flexDirection: 'row',
alignItems: 'center'
},
chatMessage_message_text: {
color: '#FFF',
fontSize: 12
}
})
If you have less number of items and want to render all items at once then you should use ScrollView as mentioned in the docs
ScrollView: Renders all elements at once, but slow if there are large number of elements.
FlatList: Renders items in a lazy mode, when they are about to appear and removes them when they leave the visible display to save memory that makes it usable for performance on large lists.
For Flatlist optimization you need to use PureComponent whenever you render the child so that it only shallow compares the props.
Also in the keyExtractor use a unique id for your item and do not depend upon the index, since when the item updates the index is not reliable and may change

Create XY chart, React-Native

How can I create basic xy chart in react-native? For example I have data:
chart_data = [
[0,0],[0,1],[1,1],[1,0],[0,0]
]
This is the points of a square. Most of all libraries offer to create line chart, which will create other line-type chart and the result for this points would be - trapeze. Help me, please
You should try MPAndroidChart, there's even a react native wrapper for it.
Use react-native-chart
import React, { StyleSheet, View, Component } from 'react-native';
import Chart from 'react-native-chart';
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white',
},
chart: {
width: 200,
height: 200,
},
});
const data = [
[0, 1],
[1, 3],
[3, 7],
[4, 9],
];
class SimpleChart extends Component {
render() {
return (
<View style={styles.container}>
<Chart
style={styles.chart}
data={data}
verticalGridStep={5}
type="line"
/>
</View>
);
}
}
Note that MPAndroidChart supports Android only, whereas react-native-chart supports both Android and iOS.
Example charts:
You could try to use Canvas and its methods. There you can draw points lines or shapes...

Setting up a table layout in React Native

I'm transitioning a React project into React Native and need help setting up a grid layout in React Native. I want to set up a 5-col by x-row (number of rows may vary) view. I've played around with the react-native-tableview-simple package, but I can't specify the span of a cell. I've also tried the react-native-flexbox-grid package, which I'm able to set up columns, but I'm still not able to set the span-width of a specific cell. I wonder if there's anything I can use.
For reference, I would like my table to look something along the lines like this:
|Col 1|Col 2|Col 3|Col 4|Col 5|
|------------------------------
Row 1| Text | Yes | No |
|------------------------------
Row 2| Text | Yes | No |
|------------------------------
Row 3| Text | Dropdown |
You can do this without any packages. If each row is exactly the same doing the following should solve your problem;
export default class Table extends Component {
renderRow() {
return (
<View style={{ flex: 1, alignSelf: 'stretch', flexDirection: 'row' }}>
<View style={{ flex: 1, alignSelf: 'stretch' }} /> { /* Edit these as they are your cells. You may even take parameters to display different data / react elements etc. */}
<View style={{ flex: 1, alignSelf: 'stretch' }} />
<View style={{ flex: 1, alignSelf: 'stretch' }} />
<View style={{ flex: 1, alignSelf: 'stretch' }} />
<View style={{ flex: 1, alignSelf: 'stretch' }} />
</View>
);
}
render() {
const data = [1, 2, 3, 4, 5];
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
{
data.map((datum) => { // This will render a row for each data element.
return this.renderRow();
})
}
</View>
);
}
}
After looking here for answers I discovered a really great library that behaves much like Bootstrap tables. I have found layout with React Native very challenging but this library delivers predictable layout results.
React Native Easy Grid
I agree that basic flex tables should be built in to React Native but until they are this library worked great for me.
Though it is an old post but I was looking for something similar asked in the question,
I have brainstormed and havoked the internet for the solution and the best solution I got was to import the react-native-table-component package to my project and prepare a decent table layout for my application to display data. There might be many more souls figuring out a way to do this and may I recommend this link to all your answers:This link is the npm package installer link which have explanation to all the code and have examples
Using functional components:
(Specify the number of rows and columns in the array)
Create a Row component
function Row({ column }) {
return (
<View style={styles.rowStyle}>
{column.map((data) => (
<Cell data={data} />
))}
</View>
);
}
Create a Cell component
function Cell({ data }) {
return (
<View style={styles.cellStyle}>
<Text>{data}</Text>
</View>
);
}
Create a Grid component
function Grid() {
const data = [
[15, 14, 13, 12],
[11, 10, 9, 8],
[7, 6, 5, 4],
[0, 1, 2, 3],
];
return (
<View style={styles.gridContainer}>
{data.map((column) => (
<Row column={column} />
))}
</View>
);
}
Style the components:
const styles = StyleSheet.create({
gridContainer: {
width: 220,
},
rowStyle: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-around",
},
cellStyle: {
flex: 1,
margin: 10,
},
});