Reputation: 1742
I am trying to implement a collapsible box in react native.Its working fine for dummy data. But when i tried to list the data response from server i'm getting error.I'm using map method over the response for listing the details.But showing error evaluating this.state.details.map
.Also i'm confused to where to place the map method.Below is the code that i've tried.I refer this doc for collapsible box.
Example
class DetailedView extends Component{
constructor(props){
super(props);
this.icons = {
'up' : require('../Images/Arrowhead.png'),
'down' : require('../Images/Arrowhead-Down.png')
};
this.state = {
title : props.title,
expanded : true,
animation : new Animated.Value()
};
}
toggle(){
let initialValue = this.state.expanded? this.state.maxHeight + this.state.minHeight : this.state.minHeight,
finalValue = this.state.expanded? this.state.minHeight : this.state.maxHeight + this.state.minHeight;
this.setState({
expanded : !this.state.expanded
});
this.state.animation.setValue(initialValue);
Animated.spring(
this.state.animation,
{
toValue: finalValue
}
).start();
}
_setMaxHeight(event){
this.setState({
maxHeight : event.nativeEvent.layout.height
});
}
_setMinHeight(event){
this.setState({
minHeight : event.nativeEvent.layout.height
});
}
state = {details: []};
componentWillMount(){
fetch('https://www.mywebsite.com' + this.props.navigation.state.params.id )
.then((response) => response.json())
.then((responseData) =>
this.setState({
details:responseData
})
);
}
render(){
let icon = this.icons['down'];
if(this.state.expanded){
icon = this.icons['up'];
}
return this.state.details.map(detail =>
<Animated.View
style={[styles.container,{height: this.state.animation}]}>
{detail.data.curriculum.map(curr =>
<View onLayout={this._setMinHeight.bind(this)}>
<Card>
<CardSection>
<View style={styles.thumbnailContainerStyle}>
<Text style={styles.userStyle}>
Hii
</Text>
</View>
<TouchableHighlight onPress={this.toggle.bind(this)}
underlayColor="#f1f1f1">
<Image style={styles.buttonImage} source={icon}></Image>
</TouchableHighlight>
</CardSection>
</Card>
</View>
<View style={styles.body} onLayout={this._setMaxHeight.bind(this)}>
{this.props.children}
<Card>
<CardSection>
<Text>{this.props.navigation.state.params.id}</Text>
</CardSection>
</Card>
</View>
)}
</Animated.View>
);
}
}
This is the screenshot for working code with dummy data
Upvotes: 0
Views: 873
Reputation: 1609
1. Solving the Error :
The API call you are making is asynchronous and once the API is called, the code continues to execute before getting the response from the API. The component tries to map through this.state.details
before there are any details.
A solution here is that you need to set an ActicityIndicator/Loader initially when component is mounted and once you get the details/response from the API, the state changes and then you can map through this.state.details
Add empty details array to your initial state.
state = { details:[] }
Then put your return this.state.details.map(detail....
Inside an if condition like this
if(this.state.details.length > 0) {
<map here>
} else {
return <ActivityLoader />
}
2. Where to place the map methiod
You need to put it inside a function and call that function from within you render method.
showDetailsFunction() {
return this.state.details.map(detail =>
}
render() {
return(
{this.showDetailsFunction()}
)
}
Upvotes: 1