I'm new to React Native` and I've been trying to create a view with the number of buttons dynamically created from the data that I fetch from the API.
One of my problems is that the data that is returned doesn't have any name that I can point like item.number
.
First I tried to do a <Flatlist/>
but I wasn't getting the design that I wanted, like this:
so now I'm trying to make in a different way, but I'm always getting the error:
Cannot read property '0' of undefined
data.json:
{
"sEcho":0,
"iTotalRecords":"75",
"iTotalDisplayRecords":"73",
"aaData":[
[
"1",
"1",
"Consumidor Final",
"999999990",
"",
"",
null,
", ",
"21110000",
"1",
"1",
"1"
],
[
"2",
"1000",
"xxxxxx",
"xxxxx",
"",
"",
null,
", ",
"xxxx",
"15",
"1",
"1"
]
]
}
How I am fetching the data;
getClientes = async (token, opcao, search, pag, numRows) => {
var url = "https://xxxx/xxxx/xxx/xxxx/xxx/tabelas/clientes?_token=" + token + "&opcao= " + opcao + "&search=&pag=&numRows=" + numRows;
fetch(url)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
dataSource: responseJson.aaData,
isLoading: false,
numRows: responseJson.iTotalDisplayRecords
})
console.log(responseJson.iTotalDisplayRecords + " total");
console.log("CLIENTES: " + responseJson.aaData[0][2]);
console.log(this.state.dataSource[0][2]);
})
.catch((error) => {
console.log(error);
})
}
How I render the buttons:
renderClientes = (numRows, data) => {
console.log(numRows + "azxcvb");
console.log(data.length + "render Clientes");
const views = [];
for (let i = 0; i <= numRows; i++) {
for (let j = 0; j <= 11; j++) {
views.push(
<TouchableOpacity style={{ flex: 1, flexDirection: 'row', marginBottom: 3 }} key={i}>
<View style={{ flex: 1, justifyContent: 'center', marginLeft: 5 }}>
<Text style={{ fontSize: 18, color: 'green' }}>
{data[i][j]}
</Text>
</View>
</TouchableOpacity>
);
}
}
return views;
}
then:
render() {
return (
...
(this.state.numRows != 0) ? this.renderClientes(this.state.numRows, this.state.dataSource) : null)
}
How can I solve my problem? And if there is any easier way to do this, what is?
It looks like your numRows
is 73
, but your array only has 2 sets of rows in it?
Usually it's better to .map
through an array, so it will automatically go through each item. Something like this:
renderClientes = (numRows, data) => {
console.log(numRows + "azxcvb");
console.log(data.length + "render Clientes");
return data.map((row, i) =>
row.map((item, j) => (
<TouchableOpacity style={{ flex: 1, flexDirection: 'row', marginBottom: 3 }} key={`${i},${j}`}>
<View style={{ flex: 1, justifyContent: 'center', marginLeft: 5 }}>
<Text style={{ fontSize: 18, color: 'green' }}>
{item}
</Text>
</View>
</TouchableOpacity>
))
);
}
Your getting this error
error: Cannot read property '0' of undefined, cause you are looping throught an number array n+1 times.
To Fix this just assign your setState like this:
this.setState({
dataSource: responseJson.aaData,
isLoading: false,
numRows: responseJson.iTotalDisplayRecords - 1
})
And as Austin Greco already pointed out, i would go for map also, trust me, it will make everything easier when working with arrays in React, and in JavaScript.
First of all a recommendation for your API:
let url = "https://clientes?_token=" + token + "&opcao= ";
Never send tokens on the URL because it's pretty easy to hack them. You can send hidden data on your headers.
As @Austin Greco said numRows
is '73'
, but your array only has 2 sets of rows. I recommend sending numRows
as an integer instead of a string.
Also for building complex interfaces from data, you should use objects that help you describe better your data, instead of an array of arrays ( aaData
) as you have. Taking the image you show us:
You can have an object like:
{
gt: 'GT 2019/01',
name: 'Luis Filipe Gomes Rodrigues',
total: '179,90 €',
open: true,
nif: 9999999999,
date: '01/01/2019',
}
instead of having
arr = ['GT 2019/01', 'Luis Filipe Gomes Rodrigues', '179,90 €', true, 9999999999, '01/01/2019']
name = arr[1]
So I took some time to create an snack for you to follow up: @abranhe/clients-view it looks something like this:
Wrap the code:
import React, { Component } from 'react';
import {
View,
Text,
Image,
StyleSheet,
TouchableOpacity,
Dimensions,
ScrollView,
} from 'react-native';
import { AntDesign } from '@expo/vector-icons';
import data from './data.js';
export default class StackOverflowAnswer extends Component {
constructor(props) {
super(props);
this.state = {
data: data,
isLoading: false,
};
}
renderClientLeft(client) {
return (
<View style={styles.clientLeft}>
<Text style={styles.gt}>GT {client.gt}</Text>
<Text style={styles.name} numberOfLines={1}>
{client.name}
</Text>
<Text style={styles.nifAndDate}>NIF: {client.nif}</Text>
<Text style={styles.nifAndDate}>Data: {client.date}</Text>
</View>
);
}
renderClientRight(client) {
let hoursColor = client.open ? '#588f40' : '#4973a3';
let hoursText = client.open ? 'Aberto' : 'Fechado';
return (
<View style={styles.clientRight}>
<View style={{ justifyContent: 'space-around' }}>
<View style={styles.total}>
<Text style={styles.name}>Total:</Text>
<Text style={styles.totalVal}>{client.total}</Text>
</View>
<View style={[{ backgroundColor: hoursColor }, styles.hours]}>
<Text style={styles.hoursText}>{hoursText}</Text>
</View>
</View>
<View style={styles.arrowContainer}>
<AntDesign name="right" color="#bf5e2a" />
</View>
</View>
);
}
renderClient(client) {
return (
<View style={styles.clientContainer}>
<View style={styles.client}>
{this.renderClientLeft(client)}
{this.renderClientRight(client)}
</View>
</View>
);
}
renderClientes = clients => {
return clients.map((client, i) => {
return (
<View key={i} style={styles.clientsSeparator}>
{this.renderClient(client)}
</View>
);
});
};
render() {
const { data } = this.state;
return (
<ScrollView style={styles.container}>
{this.renderClientes(data)}
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ededed',
marginTop: 20,
alignItems: 'center',
},
clientContainer: {
width: Dimensions.get('window').width * 0.95,
borderWidth: 1,
borderColor: '#000000',
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.4,
shadowRadius: 1,
backgroundColor: '#ffffff',
},
client: {
flexDirection: 'row',
borderRadius: 1,
margin: 4,
},
clientLeft: {
width: '60%',
marginVertical: 5,
},
clientRight: {
justifyContent: 'space-between',
flexDirection: 'row',
height: '100%',
width: '40%',
},
gt: {
fontWeight: '700',
color: '#bf5e2a',
margin: 2,
},
name: {
fontWeight: '700',
margin: 2,
},
nifAndDate: {
color: '#8a8a8a',
margin: 2,
},
arrowContainer: {
justifyContent: 'center',
alignItems: 'center',
},
totalVal: {
color: '#bf5e2a',
marginLeft: 10,
},
total: {
flexDirection: 'row',
},
hours: {
width: '70%',
justifyContent: 'center',
alignItems: 'center',
},
hoursText: {
color: '#ffffff',
margin: 5,
},
clientsSeparator: {
marginBottom: 5,
},
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.