Reputation: 3636
i am not adding reducers and actions here because thats working fine , im getting the banner objects
from the server .
Here the problem is when i do console.log(this.props.banner_list)
in the render. it seems that render method getting called two times and for the first time this.props.banner_list
is undefined and its throwing error when i try to show the objects inside the view. And second time when it renders its showing the this.props.banner_list
correctly in the console
. i didnt understand whats happening here. somebody please help me
class App extends Component<Props> {
componentDidMount(){
this.props.getBanners()
}
render() {
console.log(this.props)// here iam logging the props
return (
<View style={styles.container}>
// its throwing error so i comment it , i can see the render
// getting called two times. first time its undefined .
{banner_list.banners.banners.map(obj=>{
return(
<Text>{obj.title}</Text>
)
})}
</View>
);
}
function mapStateToProps(state){
return {
banners_list:state.banners
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({getBanners}, dispatch)
}
Upvotes: 0
Views: 521
Reputation: 7348
Re "it seems that render method getting called two times": Correct, it gets called twice. When your component gets mounted, render()
is called. This triggers componentDidMount()
to get called. When componentDidMount()
gets called, it calls this.props.getBanners()
as in your code. This triggers a re-render, which calls render()
for the second time.
Re "for the first time this.props.banner_list is undefined" Correct. As mentioned above, the first render occurs BEFORE componentDidMount()
is called, and therefore before this.props.getBanners()
is called. At the point, this.props
exists so an error is not thrown, but it does not yet contain a banners
field, so it simply returns undefined
.
Re "its throwing error when i try to show the objects inside the view" This occurs because if you try to render an undefined object inside a view, it throws an error. During this initial render, this.props.banners
is undefined, hence the error.
The solution is to CONDITIONALLY RENDER the view. If you do <View>{a && b}</View>
, if a
is false then Javascript automatically renders this as <View>null</View>
without bothering to check what b
is. Thus, re-write your code as follows:
class App extends Component<Props> {
componentDidMount(){
this.props.getBanners()
}
render() {
console.log(this.props)// here iam logging the props
return (
<View style={styles.container}>
// its throwing error so i comment it , i can see the render
// getting called two times. first time its undefined .
{banner_list.banners && banner_list.banners.banners.map(obj=>{
return(
<Text>{obj.title}</Text>
)
})}
</View>
);
}
function mapStateToProps(state){
return {
banners_list:state.banners
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({getBanners}, dispatch)
}
All I've added there ^^ is banner_list.banners &&
before banner_list.banners.banners.map
etc
Upvotes: 2
Reputation: 1082
What's happening is that when the App
component renders for the first time, your redux store state banners
is probably undefined. After the component mounts, calling this.props.getBanners
will basically trigger an update to the redux store, which will in turn dispatch new props to the App component.
When the component receives new props, it will re-render based on the props received from the redux store.
So, while trying to access banners_list.banners.banners.map
, an error will be returned on the first render because banners_list
is empty. To mitigate this, you'll need to add a check in your render method like this...
render() {
const { banners_list } = this.props;
return (
<View style={styles.container}>
{
banners_list &&
banners_list.banners.banners.map(obj=> (<Text>{obj.title}</Text>))
}
</View>
);
}
Upvotes: 1
Reputation: 11
render() {
console.log(this.props)// here iam logging the props
return (
<View style={styles.container}>
// its throwing error so i comment it , i can see the render
// getting called two times. first time its undefined .
{banner_list.banner && banner_list.banners.banners.map(obj=>{
return(
<Text>{obj.title}</Text>
)
})}
</View>
);
}
You could change that line of code. maybe what is happening is at the start of your state I imagine your redux state at first something like this
{
banners:{}
}
and after
{
banners:{
banners:{
banners:[
{title:'Hello world'}
]
}
}
}
The problem is whenever you are trying to get a property that is undefined it will return an error so at first, you could ask for that property.
Upvotes: 1