How can we create a dynamic list of objects like Views or Texts, dynamically, in a loop in React Native or React.JS from a JSON response from a REST API ?
The objective is to create a dynamic interface with buttons for adding and removing elements like that :
First, we will use the data variable to store a JSON reponse (later you can change it with the API response with a fetch() function), it will contains 3 elements.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | [
{
"id" : "01" ,
"name" : "Charlie" ,
},
{
"id" : "02" ,
"name" : "Tango" ,
},
{
"id" : "03" ,
"name" : "Delta" ,
}
]
|
Then, we will create the json variable to store the parsed JSON from the data variable. It means, the data variable is only a text string and the json variable is a JSON object, so we can do json[0].id for example.
We can put the json variable as a state so if the JSON changes, the UI with refresh automaticaly.
Here is what it should look likes in your code, in the constructor of your class :
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | export default class DynamicList extends React.Component {
constructor(props) {
super (props);
let data = `
[
{
"id" : "01" ,
"name" : "Charlie" ,
},
{
"id" : "02" ,
"name" : "Tango" ,
},
{
"id" : "03" ,
"name" : "Delta" ,
}
]`;
let json = JSON.parse(data);
console.log( 'json ' , json);
this .state = {
list: json,
};
}
[...]
|
Now, to display a list from the state list (it will be this.state.list), we will use the map() function in render(), before the return, to create as many objects that we have elements in the list array.
In your map() function, you will have 2 parameters : data and i. You will have to put the i, the incremental variable, as a “key” in each object you will return as a new element – here, it’s <TouchableOpacity> :
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | render() {
const soldierList = this .state.contracts.map((data, i) => {
return (
<TouchableOpacity
key={i}
>
<View
style={{
flexDirection: 'row' ,
justifyContent: 'flex-start' ,
paddingTop: 5,
paddingBottom: 5,
}}
>
<Text style={{ fontFamily: 'Gotham-Medium' , color: '#8DA8C7' }}>
{dateShort(data.datestart)}
</Text>
</View>
<View style={{ flexDirection: 'row' , right: 0, position: 'absolute' , bottom: 5 }}>
<MaterialCommunityIcons
name= "cross"
style={{ color: '#0261D2' , lineHeight: 20 }}
/>
</View>
</View>
</TouchableOpacity>
);
});
return (
<ScrollView style={{ backgroundColor: '#f6f6f6' , height: '100%' , width: '100%' }}>
{ this .state.list.length < 1 && (
<View style={{ alignItems: 'center' }}>
<Text style={{ fontWeight: 'bold' , color: '#0361d2' , fontFamily: 'Gotham-Medium' }}>
Empty list !!!
</Text>
</View>
)}
{ this .state.list.length >= 1 && <View>{soldierList}</View>}
</ScrollView>
);
}
|
UPDATE (SOLUTION 2)
We can optimize it by testing directly the length of the array, making less code in the return :
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | render() {
const soldierList = this .state.contracts.length ? this .state.contracts.map((data, i) => {
return (
<TouchableOpacity
key={i}
>
<View
style={{
flexDirection: 'row' ,
justifyContent: 'flex-start' ,
paddingTop: 5,
paddingBottom: 5,
}}
>
<Text style={{ fontFamily: 'Gotham-Medium' , color: '#8DA8C7' }}>
{dateShort(data.datestart)}
</Text>
</View>
<View style={{ flexDirection: 'row' , right: 0, position: 'absolute' , bottom: 5 }}>
<MaterialCommunityIcons
name= "cross"
style={{ color: '#0261D2' , lineHeight: 20 }}
/>
</View>
</View>
</TouchableOpacity>
);
}) : (
<View style={{ alignItems: 'center' }}>
<Text style={{ fontWeight: 'bold' , color: '#0361d2' , fontFamily: 'Gotham-Medium' }}>
Empty list !!!
</Text>
</View>
);
return (
<ScrollView style={{ backgroundColor: '#f6f6f6' , height: '100%' , width: '100%' }}>
{soldierList}
</ScrollView>
);
}
|