TLDR; When you use default parameters to set default props in a React component you don't get proptypes validation and also you need to define those default parameters in every class method in which you want to use those props.
Recently, in a code review that I was doing, I saw a code like this in a React component:
render() {
const {
count = 0
} = this.props;
return <div>{ count }</div>
}
My first thought was that it was wrong because you should define default props adding a property called defaultProps
or using an static method.
// Setting a defaultProps property
class App extends React.Component {
render() {
const {count} = this.props;
return <div>
{count}
</div>
}
}
App.defaultProps = {
count: 0
}
// Adding an static method to the component
class App extends React.Component {
static defaultProps = {
count: 0
}
render() {
const {count} = this.props;
return <div>
{count}
</div>
}
}
But after trying the code, and to my surprise, it worked! So I was wondering if this is a valid practice inside a React component since I haven't seen it in any place. Even thought this works there are a few things that won't work but they aren't so obvious right away.
PropTypes validation
Acording to React docs:
The propTypes typechecking happens after defaultProps are resolved, so typechecking will also apply to the defaultProps.
This means, that when you define proptypes, its validations are made in the props AND the default props that you set either with static defaultProps
or defaultProps
method but not when you use default paramaters.
So, for example if we do this:
class App extends React.Component {
render() {
const { count } = this.props
return <div>{ count }</div>
}
}
App.propTypes = {
count: PropTypes.number
}
App.defaultProps = {
count: 'hello'
}
We're going to get this warning:
index.js:1446 Warning: Failed prop type: Invalid prop `count` of type `string` supplied to `App`, expected `number`.
But if we use default parameters:
class App extends React.Component {
render() {
const { count = 'hello' } = this.props
return <div>{ count }</div>
}
}
App.propTypes = {
count: PropTypes.number
}
We won't get any errors or warnings because React doesn't have any way to make a runtime analysis.
Possible inconsistency in props values between class methods
When we define defaultProps
the values define inside of it will be available on every method inside a React component but if we use defalt parameters we must define the default value on every method. Let me explain this with an example.
class App extends React.Component {
componentDidMount() {
const { count } = this.props
console.log('count in CDM: ', count)
}
render() {
const { count } = this.props
console.log('count in Render: ', count)
return <div>{ count }</div>
}
}
App.propTypes = {
count: PropTypes.number
}
App.defaultProps = {
count: 10
}
If we run this code, we are going to get:
count in Render: 10
count in CDM: 10
As you can see, on every method the default value will be the same so we can be sure that if the prop is not passed the default value will be the same in all places.
In contrast, if you use default parameters the prop could be different on every class method.
class App extends React.Component {
componentDidMount() {
const { count } = this.props
console.log('count in CDM: ', count)
}
render() {
const { count = 10 } = this.props
console.log('count in Render: ', count)
return <div>{ count }</div>
}
}
App.propTypes = {
count: PropTypes.number
}
In this example we will get this:
count in Render: 10
count in CDM: undefined
It's very bad to have a different value for the same prop in a different part of the component.
Final thoughts
This kind of things reminds me that almost always it's possible to write wrong code that just works so we need to understand the impact of the decision that we made when we write applications. This can be seen as a problem with a small component when you can keep an eye on everything that is happening, but once the application gets bigger it gets very hard to track down this kind of bugs.
Top comments (1)
Great article, I also wanted to add that defaultProps are visible within the React Dev tools compared to default parameters, which for me adds a bit more information when debugging. I've read that the defaultProps property would be deprecated but it's stick kicking after RC 17!