Thameem
Thameem

Reputation: 3636

react native redux props not getting updated when the screen render

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

Answers (3)

gkeenley
gkeenley

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

Ladi Adenusi
Ladi Adenusi

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

Dev Trillo
Dev Trillo

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

Related Questions