@@ -174,6 +174,53 @@ module.exports = {
174
174
) ;
175
175
}
176
176
177
+ /**
178
+ * Returns true if the given node is a React Component lifecycle method
179
+ * @param {ASTNode } node The AST node being checked.
180
+ * @return {Boolean } True if the node is a lifecycle method
181
+ */
182
+ function isNodeALifeCycleMethod ( node ) {
183
+ var nodeKeyName = ( node . key || { } ) . name ;
184
+ return (
185
+ node . kind === 'constructor' ||
186
+ nodeKeyName === 'componentWillReceiveProps' ||
187
+ nodeKeyName === 'shouldComponentUpdate' ||
188
+ nodeKeyName === 'componentWillUpdate' ||
189
+ nodeKeyName === 'componentDidUpdate'
190
+ ) ;
191
+ }
192
+
193
+ /**
194
+ * Returns true if the given node is inside a React Component lifecycle
195
+ * method.
196
+ * @param {ASTNode } node The AST node being checked.
197
+ * @return {Boolean } True if the node is inside a lifecycle method
198
+ */
199
+ function isInLifeCycleMethod ( node ) {
200
+ if ( node . type === 'MethodDefinition' && isNodeALifeCycleMethod ( node ) ) {
201
+ return true ;
202
+ }
203
+
204
+ if ( node . parent ) {
205
+ return isInLifeCycleMethod ( node . parent ) ;
206
+ }
207
+
208
+ return false ;
209
+ }
210
+
211
+ /**
212
+ * Checks if a prop init name matches common naming patterns
213
+ * @param {ASTNode } node The AST node being checked.
214
+ * @returns {Boolean } True if the prop name matches
215
+ */
216
+ function isPropAttributeName ( node ) {
217
+ return (
218
+ node . init . name === 'props' ||
219
+ node . init . name === 'nextProps' ||
220
+ node . init . name === 'prevProps'
221
+ ) ;
222
+ }
223
+
177
224
/**
178
225
* Checks if a prop is used
179
226
* @param {ASTNode } node The AST node being checked.
@@ -536,11 +583,14 @@ module.exports = {
536
583
node . id . properties [ i ] . value . type === 'ObjectPattern'
537
584
) ;
538
585
// let {firstname} = props
539
- var statelessDestructuring = node . init . name === 'props' && utils . getParentStatelessComponent ( ) ;
586
+ var genericDestructuring = isPropAttributeName ( node ) && (
587
+ utils . getParentStatelessComponent ( ) ||
588
+ isInLifeCycleMethod ( node )
589
+ ) ;
540
590
541
591
if ( thisDestructuring ) {
542
592
properties = node . id . properties [ i ] . value . properties ;
543
- } else if ( statelessDestructuring ) {
593
+ } else if ( genericDestructuring ) {
544
594
properties = node . id . properties ;
545
595
} else {
546
596
continue ;
@@ -776,7 +826,10 @@ module.exports = {
776
826
// let {props: {firstname}} = this
777
827
var thisDestructuring = destructuring && node . init . type === 'ThisExpression' ;
778
828
// let {firstname} = props
779
- var statelessDestructuring = destructuring && node . init . name === 'props' && utils . getParentStatelessComponent ( ) ;
829
+ var statelessDestructuring = destructuring && isPropAttributeName ( node ) && (
830
+ utils . getParentStatelessComponent ( ) ||
831
+ isInLifeCycleMethod ( node )
832
+ ) ;
780
833
781
834
if ( ! thisDestructuring && ! statelessDestructuring ) {
782
835
return ;
@@ -831,6 +884,18 @@ module.exports = {
831
884
}
832
885
} ,
833
886
887
+ ObjectPattern : function ( node ) {
888
+ // If the object pattern is a destructured props object in a lifecycle
889
+ // method -- mark it for used props.
890
+ if ( isNodeALifeCycleMethod ( node . parent . parent ) ) {
891
+ node . properties . forEach ( function ( property , i ) {
892
+ if ( i === 0 ) {
893
+ markPropTypesAsUsed ( node . parent ) ;
894
+ }
895
+ } ) ;
896
+ }
897
+ } ,
898
+
834
899
ObjectExpression : function ( node ) {
835
900
// Search for the proptypes declaration
836
901
node . properties . forEach ( function ( property ) {
0 commit comments