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.
[
{
"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 :
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> :
render() {
// HERE WE MAKE OUR LIST OF OBJECTS
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>
);
});
// NOW WE CAN DISPLAY IT, IF THE LIST IS EMPTY WE GOT THE EMPTY LIST MESSAGE
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 :
render() {
// HERE WE MAKE OUR LIST OF OBJECTS
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>
);
// NOW WE CAN DISPLAY IT, IF THE LIST IS EMPTY WE GOT THE EMPTY LIST MESSAGE
return (
<ScrollView style={{ backgroundColor: '#f6f6f6', height: '100%', width: '100%' }}>
{soldierList}
</ScrollView>
);
}