[英]React native make “buttons” dynamically from API
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. 我是React Native的新手,我一直在尝试创建一个视图,其中包含从我从API获取的数据动态创建的按钮数量。
One of my problems is that the data that is returned doesn't have any name that I can point like item.number
. 我的一个问题是返回的数据没有任何我可以指向item.number
。
First I tried to do a <Flatlist/>
but I wasn't getting the design that I wanted, like this: 首先,我试图做一个<Flatlist/>
但我没有得到我想要的设计,像这样:
so now I'm trying to make in a different way, but I'm always getting the error: 所以现在我想尝试以不同的方式,但我总是得到错误:
Cannot read property '0' of undefined 无法读取未定义的属性“0”
data.json: 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? 看起来你的numRows
是73
,但你的数组中只有2组行?
Usually it's better to .map
through an array, so it will automatically go through each item. 通常最好通过数组.map
,因此它会自动遍历每个项目。 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. 错误:无法读取未定义的属性“0”,导致您循环遍历数字数组n + 1次。
To Fix this just assign your setState like this: 要解决这个问题,只需像这样分配你的setState:
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. 正如Austin Greco已经指出的那样,我也会选择地图,相信我,在React和JavaScript中使用数组时,它会使一切变得更容易。
First of all a recommendation for your API: 首先推荐您的API:
let url = "https://clientes?_token=" + token + "&opcao= ";
Never send tokens on the URL because it's pretty easy to hack them. 永远不要在URL上发送令牌,因为它很容易被破解。 You can send hidden data on your headers. 您可以在标题上发送隐藏数据。
As @Austin Greco said numRows
is '73'
, but your array only has 2 sets of rows. 正如@Austin Greco所说numRows
是'73'
,但你的数组只有2组行。 I recommend sending numRows
as an integer instead of a string. 我建议将numRows
作为整数而不是字符串发送。
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. 另外,对于从数据构建复杂接口,您应该使用帮助您更好地描述数据的对象,而不是像您一样使用数组数组( aaData
)。 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: 所以我花了一些时间为你创建一个零食跟进: @ abranhe / clients-view它看起来像这样:
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,
},
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.