2

I have a parent component called "Component_A" and i have a child component "Component_B". I am trying to get data from server in the parent component and pass it down to child component as props. But my props will not have values in it before i make the ajax call in "componentDidMount" function in parent "Component_A". So i am trying to set defaultProps in child component "Component_B" using the "getDefaultProps". But looks like it doesnt work!

var Component_A = React.createClass({
        componentDidMount : function(){
            //Get data from server and set it in state variable called "data"
        },
        render : function(){
            return (
                <ComponentB sampleData={this.state.data} />
            )
        }
    })

    var ComponentB = React.createClass({
        getDefaultProps : function (){
            return {
                data : {
                  vehicle : {
                      make :{
                         name : "Ford"
                      },
                      model : {
                         name : "Focus"
                      }
                  }
                }
            }
        },
        render : function(){
            return (
                 <div> {this.props.data.vehicle.make.name} </div>
            )
        }
    })

when i load the page, i get "Uncaught TypeError: Cannot read property 'make' of undefined"

user3807940
  • 841
  • 2
  • 8
  • 16

2 Answers2

0
   render : function(){
            <ComponentB sampleData={this.state.data} />
        }

Everything ok, maybe you forget return here

trquoccuong
  • 2,857
  • 2
  • 20
  • 26
0

Change A's render to this-

render : function(){ 
    if(this.state.data){
        return ( <ComponentB data={this.state.data} /> );
    }
    else{
        return ( <ComponentB />);
    }
 }
hazardous
  • 10,627
  • 2
  • 40
  • 52
  • 1
    I think this should work but is this the best way of doing it? I dont think so!! – user3807940 Dec 24 '15 at 10:22
  • This issue is coming because instead receiving discrete props, Component B is taking all of them in one big object. And Component A sends a null value for this object, overriding the default props defined in B. When taking object props, ideally, one must merge the incoming values with defaults, either in componentWillReceiveProps, or render. – hazardous Dec 24 '15 at 10:47
  • So does it mean that using complex props is not encouraged? I mean props which has nested objects? – user3807940 Dec 24 '15 at 11:47
  • No, that's not the case. Most every component supports "style" which is composite. Let's look at how getDefaultProps works to understand the issue here. getDefaultProps function is called only once and the results are cached for all instances of a component. The default props take effect when the value of the prop is "undefined". In your case, A is sending the value as "null", which is not undefined. Hence defaultProps are not applied. – hazardous Dec 24 '15 at 11:59
  • Ahh.. now i get this... So there are 2 possible solutions i suppose!! One is the thing which you said and the other way might be to keep my data simple may be? instead of nested objects, might be i only send simple object? Something like { makeName : "", modelName: "" } Am i right? – user3807940 Dec 24 '15 at 12:05
  • Yes. Keep props flat as much as possible, it helps to understand the component as well. You can always use the object [destructuring assignment](https://facebook.github.io/react/docs/transferring-props.html) to spread a complex object as independent props to your components. – hazardous Dec 24 '15 at 12:20