In React Native, how can I specify an alternative text to use if data is not available?
For example, in the following code, how would I specify to display "no skills, yet", if the skills array is empty?
<View>
<Text>
Skills
</Text>
<View>{
p.skills && p.skills.map( skill =>
<Text key={skill}>
{ skill }
</Text>
)
}</View>
</View>
You could either save the desired output in a variable before rendering:
let skillText = (<Text>{'no skills, yet'}</Text>);
if (p.skills && p.skills.length > 0) {
skillText = p.skills.map( skill =>
<Text key={skill}>
{ skill }
</Text>
);
}
...some more code...
<View>
<Text>
Skills
</Text>
<View>{ skillText }</View>
</View>
Or use a ternary directly in the jsx:
<View>
<Text>
Skills
</Text>
<View>{
(p.skills && p.skills.length > 0) ? p.skills.map( skill =>
<Text key={skill}>
{ skill }
</Text>
) : 'no skills, yet'
}</View>
</View>
First way (short one):
<View>
<Text>
Skills
</Text>
<View>
{
(p.skills && p.skills.length > 0) ? p.skills.map( skill =>
<Text key={skill}>
{ skill }
</Text>
) : (
<Text>no skills, yet</Text>
)
}
</View>
</View>
Second way: Extract the list rendering into a separate method
renderSkills = () => {
if (p.skills && p.skills.length > 0) {
return p.skills.map( skill =>
<Text key={skill}>
{ skill }
</Text>
)
} else {
return (
<Text>no skills, yet</Text>
)
}
}
render() {
return (
<View>
<Text>
Skills
</Text>
<View>
{this.renderSkills()}
</View>
</View>
)
}
PS: Please consider to use FlatList instead of rendering rows using Text (it helps a lot with performance)
Related
Hi, I used if condition like below, but there is nothing rendering on the screen. By the way, there is 'MAVI' in leader array
renderall() {
return this.state.leader.map(alb => {
if(alb.Renk == 'MAVI') {
<View style={styles.container} key={counter = counter + 1}>
<Text style={[styles.textStyle, {marginLeft:'5%'}]}> {alb.Tescil_No} </Text>
<Text style={[styles.textStyle, {marginLeft:'6%'}]}> {alb.GumrukAdi} </Text>
<Text style={[styles.textStyle, { marginLeft:'5%'}]}> {alb.ACIKLAMA} </Text>
</View>
}
});
}
You're missing a return in your .map. Notice that inside the if statement I am returning the items being mapped.
renderall() {
return this.state.leader.map(alb => {
if(alb.Renk == 'MAVI') {
return (
<View style={styles.container} key={counter = counter + 1}>
<Text style={[styles.textStyle, {marginLeft:'5%'}]}> {alb.Tescil_No} </Text>
<Text style={[styles.textStyle, {marginLeft:'6%'}]}> {alb.GumrukAdi} </Text>
<Text style={[styles.textStyle, { marginLeft:'5%'}]}> {alb.ACIKLAMA} </Text>
</View>
);
}
});
}
This article explains in more detail how the .map function works
https://codeburst.io/learn-understand-javascripts-map-function-ffc059264783
Here is a very small example showing how to use the .map function. Notice the return statement.
let leaders = ['Tom','Jerry','Mike'];
let mappedLeaders = leaders.map((leader, index) => {
return `${leader} is number ${index}`; // notice that I am returning here
})
console.log(mappedLeaders)
Here is an example of using a .map with an if statement inside it. Notice we will get undefined for the first item in the mappedLeaders as we are not returning anything for the first item because Tom is excluded due to the fact that his name is too short.
let leaders = ['Tom','Jerry','Mike'];
let mappedLeaders = leaders.map((leader, index) => {
if (leader.length > 3) {
return `${leader} is number ${index}`; // notice that I am returning here
}
});
console.log(mappedLeaders)
I am new to react-native and trying to make a GSTCalculator App. I take values from the user on calculator screen and show calculated values on Result screen. My problem is that the calculated values don't show up immediately on the Result screen. I have even used async and await. But it only shows first calculated value.
calculate = async() => {
await this.calculateSum();
this.props.navigation.navigate('Result', {prodCost: this.state.prodCost,
mfdProfitMargin: this.state.mfdProfitMargin, mCost: this.state.mCost, whProfit: this.state.whProfit,
rtProfit: this.state.rtProfit, cgst: this.state.cgst, sgst: this.state.sgst, igst: this.state.igst,
igstV: this.state.igstV, m2wV: this.state.m2wV, w2rT: this.state.w2rT, whProfitV: this.state.whProfitV,
cgstV: this.state.cgstV, sgstV: this.state.sgstV, w2rV :this.state.w2rV, rtProfitV: this.state.rtProfitV })
}
calculateSum = () => {
this.setState({mCost: Number(this.state.prodCost) + Number(this.state.mfdProfitMargin)});
this.setState({igstV: (Number(this.state.mCost)*Number(this.state.igst))/100});
this.setState({m2wV: Number(this.state.mCost) + Number(this.state.igstV)});
this.setState({whProfitV: (this.state.m2wV)*Number(this.state.whProfit)/100});
this.setState({w2rT: Number(this.state.m2wV) + Number(this.state.whProfitV)});
this.setState({cgstV: (this.state.w2rT)*Number(this.state.cgst)/100});
this.setState({sgstV: (this.state.w2rT)*Number(this.state.sgst)/100});
this.setState({w2rV: Number(this.state.w2rT) + Number(this.state.cgstV) + Number(this.state.sgstV)});
this.setState({rtProfitV: (this.state.w2rV)*Number(this.state.rtProfit)/100});
}
export default class Result extends Component {
constructor(props) {
super(props);
this.state = { pCost: this.props.navigation.state.params.prodCost, pMargin: this.props.navigation.state.params.mfdProfitMargin,
mCost:this.props.navigation.state.params.mCost, igstP: this.props.navigation.state.params.igst,
igstV: this.props.navigation.state.params.igstV, cgstP: this.props.navigation.state.params.cgst,
cgstV: this.props.navigation.state.params.cgstV, sgstP: this.props.navigation.state.params.sgst,
sgstV: this.props.navigation.state.params.sgstV, m2wV: this.props.navigation.state.params.m2wV,
whProfit: this.props.navigation.state.params.whProfit, whProfitV: this.props.navigation.state.params.whProfitV,
w2rT: this.props.navigation.state.params.w2rT, w2rV: this.props.navigation.state.params.w2rV,
rtProfit:this.props.navigation.state.params.rtProfit, rtProfitV: this.props.navigation.state.params.rtProfitV
}
}
render() {
return(
<View>
<ImageBackground source={require('../Assets/login.jpg')} style={Styles.bgImage}>
<ScrollView contentContainerStyle={GStyle.container}>
<View>
<Text style={[Styles.heading, {marginTop: 20}]}>Manufacturer to Wholesaler:</Text>
<View style={GStyle.inputView}>
<Text style={[GStyle.text, {marginTop:10}]}>Production Cost</Text>
<Text style={GStyle.resultText}>{this.state.pCost}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Profit Margin</Text>
<Text style={GStyle.resultText}>{this.state.pMargin}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Manufacture Cost</Text>
<Text style={GStyle.resultText}>{this.state.mCost}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>IGST({this.state.igstP}%)</Text>
<Text style={GStyle.resultText}>{this.state.igstV}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Invoice Value</Text>
<Text style={GStyle.resultText}>{this.state.m2wV}</Text>
</View>
</View>
<View>
<Text style={[Styles.heading, {marginTop: 20}]}>Wholesaler to Retailer:</Text>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Cost to Wholesaler</Text>
<Text style={GStyle.resultText}>{this.state.m2wV}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Profit Margin({this.state.whProfit}%)</Text>
<Text style={GStyle.resultText}>{this.state.whProfitV}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Total</Text>
<Text style={GStyle.resultText}>{this.state.w2rT}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>CGST({this.state.cgstP}%)</Text>
<Text style={GStyle.resultText}>{this.state.cgstV}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>SGST({this.state.sgstP}%)</Text>
<Text style={GStyle.resultText}>{this.state.sgstV}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Invoice Value</Text>
<Text style={GStyle.resultText}>{this.state.w2rV}</Text>
</View>
</View>
<View>
<Text style={[Styles.heading, {marginTop: 20}]}>Retailer to Consumer:</Text>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Cost to Retailer</Text>
<Text style={GStyle.resultText}>{this.state.w2rV}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>ProfitMargin({this.state.rtProfit}%)</Text>
<Text style={GStyle.resultText}>{this.state.rtProfitV}</Text>
</View>
</View>
</ScrollView>
</ImageBackground>
</View>
);
}
}
There is a lot of setting of state going I think we can reduce it and there is a little refactoring we can do to make your code easier to read.
Constructor
You are typing the same thing over and over again and it makes your constructor much harder to read than it needs to be.
In this example we have taken the the value this.props.navigation.state.params and set it to it's own variable. This means you don't have to keep typing the this.props.navigation.state.params over and over and over again.
constructor(props) {
super(props);
const params = this.props.navigation.state.params
this.state = {
pCost: params.prodCost,
pMargin: params.mfdProfitMargin,
mCost:params.mCost,
igstP: params.igst,
igstV: params.igstV,
cgstP: params.cgst,
cgstV: params.cgstV,
sgstP: params.sgst,
sgstV: params.sgstV,
m2wV: params.m2wV,
whProfit: params.whProfit,
whProfitV: params.whProfitV,
w2rT: params.w2rT,
w2rV: params.w2rV,
rtProfit:params.rtProfit,
rtProfitV: params.rtProfitV
}
}
If we use spread operator we can make this even easier, that is if you are willing to use the same name as in the object that you are passing.
constructor(props) {
super(props);
this.state = {
...this.props.navigation.state.params
}
}
However, if you use this method then you will find that some of the unique names you have chosen will be gone, replaced by the ones that are in the object that you are passing.
I am assuming that you would go with the first option (as it doesn't change the names) so I will base my next refactors on that.
Calculate Sum
There are too many setStates here, It takes time for state to set, so you could be using old values in your subsequent calculations so it is best not to use setState until you have performed all your calculations. If the values for each setState depend on the previous values then you could do something like this, only using values from the initial state where necessary.
calculateSum () => {
let mCost = Number(this.state.prodCost) + Number(this.state.mfdProfitMargin);
let igstV = mCost * Number(this.state.igst) / 100;
let m2wV = mCost + igstV;
let whProfitV = m2wV * Number(this.state.whProfit)/100;
let w2rT = m2wV + whProfitV;
let cgstV = w2rT * Number(this.state.cgst)/100;
let sgstV = w2rT * Number(this.state.sgst)/100;
let w2rV = w2rT + cgstV + sgstV;
let rtProfitV = w2rV * Number(this.state.rtProfit)/100;
return { mCost, igstV, m2wV, whProfitV, w2rT, cgstV, sgstV, w2rV, rtProfitV }
}
Here I return an object with all the updated values, that can be saved to state if we so choose.
Calculate
As the calculateSum function now returns an object with all the value that you want you could do something like this. We take the sum object that we just calculated and using a spread operator set all those objects to state. We then use a callback on the setState function to then navigate to the next page, using the spread operator again to capture all the values that in state.
calculate = () => {
let sum = this.calculateSum();
this.setState({...sum}, () => {
this.props.navigation.navigate('Result', {...this.state })
});
}
However if these values don't need to saved to state and just passed to the next screen, we could update the calculate function to something like this
calculate = () => {
let sum = this.calculateSum();
this.props.navigation.navigate('Result', {...this.state, ...sum })
}
I hope this helps you.
For more information on the spread operator in javascript see this article
https://zendev.com/2018/05/09/understanding-spread-operator-in-javascript.html
For more information on setting state check out both of these articles
https://medium.learnreact.com/setstate-is-asynchronous-52ead919a3f0
https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296
In the following, first example how do I check if the clickable element TouchableWithoutFeedback has the style named EntryBlock1?
render() {
return (
<TouchableWithoutFeedback style={styles.EntryBlock1} onPress={() => this.CheckIfHasStyles()}>
<View style={styles.redundantWrapperNumber1}>
<Text style={styles.redundantWrapperNumber2}>Click To Test For Style</Text>
</View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback style={styles.EntryBlock2} onPress={() => this.CheckIfHasStyle()}>
<View style={styles.redundantWrapperNumber1}>
<Text style={styles.redundantWrapperNumber2}>Click To Test For Style</Text>
</View>
</TouchableWithoutFeedback>
); // end return
} // end render
In the 2nd example, how can I check if TouchableWithoutFeedback has the state name EntryBlock1 ?
constructor (props) {
super(props);
this.state = {
EntryBlock1: [styles.entryBlockButton, styles.entryBlockButtonMin],
EntryBlock2: [styles.entryBlockButton, styles.entryBlockButtonMax],
}
}
render() {
return (
<TouchableWithoutFeedback style={this.state.EntryBlock1} onPress={() => this.CheckIfHasStateName()}>
<View style={styles.redundantWrapperNumber1}>
<Text style={styles.redundantWrapperNumber2}>Click To Test For Style</Text>
</View>
</TouchableWithoutFeedback>
); // end return
What I've Tried
Different stuff along the lines of the following..
CheckIfHasStyles =()=> {
var object = this.state;
var stringifiedObject = JSON.stringify(object);
var slicedObject = stringifiedObject.slice(2, 13);
if (slicedObject === 'EntryBlock1') {
alert('success');
} else {
alert('failure');
}
}
.. which actually works for one very specific example, but not when I have multiple state names as this.state gets all of them in one object and not just the state of the element clicked.
Note: My question is solely about getting attributes and their values. It is to help me develop a style of toggling styles on elements but I am only looking for attribute stuff in these answers as I would like to use attributes, if possible, for more than just toggling in the future.
You can pass it as parameter to your function directly like this:
render() {
return (
<TouchableWithoutFeedback style={styles.EntryBlock1} onPress={() => this.CheckIfHasStyles('EntryBlock1')}>
<View style={styles.redundantWrapperNumber1}>
<Text style={styles.redundantWrapperNumber2}>Click To Test For Style</Text>
</View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback style={styles.EntryBlock2} onPress={() => this.CheckIfHasStyle('EntryBlock2')}>
<View style={styles.redundantWrapperNumber1}>
<Text style={styles.redundantWrapperNumber2}>Click To Test For Style</Text>
</View>
</TouchableWithoutFeedback>
);
}
and check if you are receiving any parameter in your function and do what you want
based on If-else condition
How to add a link in the Expo.WebBrowser.openBrowserAsync(url) function. What I did Expo.WebBrowser.openBrowserAsync("{mylink}") and Expo.WebBrowser.openBrowserAsync({mylink}) does not work. What to do ? However, when I put Expo.WebBrowser.openBrowserAsync ("http://example.com"), it works well. Thanks for your help.
renderPost = ({id, titre, contenu, mylink}, i) => {
return (
<View
key={id}
style={styles.post}
>
<View style={styles.postContent}>
<Text>
{titre}
</Text>
<Text style={styles.postBody}>
{contenu}
</Text>
<Button
style={styles.paragraph}
title="Voir le site."
onPress={() => Expo.WebBrowser.openBrowserAsync("{mylink}")}
/>
<Text>{"\n\n"}</Text>
</View>
</View>
)
}
I found the solution. The code:
renderPost = ({id, titre, contenu, mylink}, i) => {
return (
<View
key={id}
style={styles.post}
>
<View style={styles.postContent}>
<Text>
{titre}
</Text>
<Text style={styles.postBody}>
{contenu}
</Text>
<Button
style={styles.paragraph}
title="Voir le site."
onPress={() => Expo.WebBrowser.openBrowserAsync(mylink)}
/>
<Text>{"\n\n"}</Text>
</View>
</View>
)
}
For example, I wanna show a list of names. So I wanted to do something like this:
var returnValue;
for (eachName of _names) {
returnValue += (
<TouchableHighlight
onPress={() => this._onPressButton}>
<Text>
{eachName}
</Text>
</TouchableHighlight>);
}
return returnValue;
However, that is not valid. Which brings me to my question: How do I concatenate a dynamic amount of JSX components in React Native.
Figures I figure it out soon as I ask stackoverflow. The code needs to be put into an array:
var returnValue = [];
for (var i = 0; i < _names.length; i++) {
returnValue.push(
<TouchableHighlight onPress={() => this._onPressButton}>
<Text>
{_names[i]}
</Text>
</TouchableHighlight>);
}
return returnValue;
There is also more information here: http://facebook.github.io/react/docs/multiple-components.html#dynamic-children
Maybe a more elegant way:
return <View>
{_names.map((eachName) => {
return (
<TouchableHighlight onPress={() => this._onPressButton}>
<Text>
{eachName}
</Text>
</TouchableHighlight>
);
})}
</View>
let returnValue = _names.map(eachName =>
<TouchableHighlight
onPress={() => this._onPressButton}>
<Text>
{eachName}
</Text>
</TouchableHighlight>);
return returnValue;