Reputation: 8897
I use pattern container/representational components.
I have CardContainer
component which fetch data from a server and pass it to a Card
component
Container component:
class CardContainer extends Component {
state = {
'card': null
}
componentDidMount() {
fetch(`${BASEURL}/api/cards/${this.props.params._id}/`)
.then(res => res.json())
.then(card => this.setState({'card': card}))
}
render() {
return <CardDetail card={this.state.card} />
}
Representational component:
class CardDetail extends Component {
render() {
return (
<div>
{this.props.card._id}
</div>
)
}
}
In that case I have an error:
Uncaught TypeError: Cannot read property '_id' of null
So render method of a child called before componentDidMount
of a parrent.
But in the case when I pass stateless function component to a child all works fine:
const FunctionChild = props => <h1>{props._id}</h1>
class CardDetail extends Component {
render() {
return (
<div>
<FunctionChild {...this.props.card} />
</div>
)
}
}
I use console.log in components render
and in a componentDidMount
method to understand the method resolution:
So componentDidMount
still called last but all works fine. Please someone explain what am I missing.
Upvotes: 1
Views: 72
Reputation: 104459
Reason is, initially you defined the card value as null
, and accessing the value of id, that's why it is throwing the error :
can not access property id of null
Because you are fetching the data from api
, it is asynchronous call
and will take time to return
the data, until you didn't get the data, value of card will be null
.
One way of fixing this is, initialise the card with {}
instead of null
, like this:
class CardContainer extends Component {
state = {
'card': {} //change this
}
componentDidMount() {
fetch(`${BASEURL}/api/cards/${this.props.params._id}/`)
.then(res => res.json())
.then(card => this.setState({'card': card}))
}
render() {
return <CardDetail card={this.state.card} />
}
Or put the check inside the child component before accessing the id value, like this:
class CardDetail extends Component {
render() {
return (
<div>
{this.props.card && this.props.card._id}
</div>
)
}
}
Upvotes: 3