@@ -34,11 +34,13 @@ import {
34
34
import { isMutable } from '../ReactiveScopes/InferReactiveScopeVariables' ;
35
35
import { assertExhaustive } from '../Utils/utils' ;
36
36
37
+ // TODO: Maybe I can consolidate some types
37
38
type SetStateCall = {
38
39
loc : SourceLocation ;
39
- invalidDeps : Map < Identifier , Place [ ] > | undefined ;
40
+ invalidDeps : DerivationMetadata ;
40
41
setStateId : IdentifierId ;
41
42
} ;
43
+
42
44
type TypeOfValue = 'ignored' | 'fromProps' | 'fromState' | 'fromPropsOrState' ;
43
45
44
46
type SetStateName = string | undefined | null ;
@@ -52,9 +54,8 @@ type DerivationMetadata = {
52
54
53
55
// TODO: This needs refining
54
56
type ErrorMetadata = {
55
- errorType : 'HoistState' | 'CalculateInRender' ;
56
- propInfo : string | undefined ;
57
- localStateInfo : string | undefined ;
57
+ errorType : TypeOfValue ;
58
+ invalidDepInfo : string | undefined ;
58
59
loc : SourceLocation ;
59
60
setStateName : SetStateName ;
60
61
} ;
@@ -102,7 +103,7 @@ function parseInstr(
102
103
// console.log(instr);
103
104
let typeOfValue : TypeOfValue = 'ignored' ;
104
105
105
- // If the instruction is destructuring a useState hook call
106
+ // TODO: Not sure if this will catch every time we create a new useState
106
107
if (
107
108
instr . value . kind === 'Destructure' &&
108
109
instr . value . lvalue . pattern . kind === 'ArrayPattern' &&
@@ -118,7 +119,6 @@ function parseInstr(
118
119
}
119
120
}
120
121
121
- // If the instruction is calling a setState
122
122
if (
123
123
instr . value . kind === 'CallExpression' &&
124
124
isSetStateType ( instr . value . callee . identifier ) &&
@@ -298,7 +298,6 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
298
298
}
299
299
}
300
300
301
- // Maybe this should run for every instruction being parsed
302
301
if ( value . kind === 'LoadLocal' ) {
303
302
locals . set ( lvalue . identifier . id , value . place . identifier . id ) ;
304
303
} else if ( value . kind === 'ArrayExpression' ) {
@@ -357,7 +356,8 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
357
356
*/
358
357
if (
359
358
setStateCalls . get ( error . setStateName ) ?. length !=
360
- effectSetStates . get ( error . setStateName ) ?. length
359
+ effectSetStates . get ( error . setStateName ) ?. length &&
360
+ error . errorType !== 'fromState'
361
361
) {
362
362
reason =
363
363
'Consider lifting state up to the parent component to make this a controlled component. (https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes)' ;
@@ -366,17 +366,9 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
366
366
'You may not need this effect. Values derived from state should be calculated during render, not in an effect. (https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state)' ;
367
367
}
368
368
369
- if ( error . propInfo !== undefined ) {
370
- description += error . propInfo ;
371
- }
372
-
373
- if ( error . localStateInfo !== undefined ) {
374
- description += error . localStateInfo ;
375
- }
376
-
377
369
throwableErrors . push ( {
378
370
reason : reason ,
379
- description : description ,
371
+ description : `You are using invalid dependencies: \n\n ${ error . invalidDepInfo } ` ,
380
372
severity : ErrorSeverity . InvalidReact ,
381
373
loc : error . loc ,
382
374
} ) ;
@@ -411,7 +403,7 @@ function validateEffect(
411
403
}
412
404
}
413
405
414
- // This might be wrong gotta double check
406
+ // TODO: This might be wrong gotta double check
415
407
let hasInvalidDep = false ;
416
408
for ( const dep of effectDeps ) {
417
409
const depMetadata = derivedTuple . get ( dep ) ;
@@ -513,23 +505,15 @@ function validateEffect(
513
505
instr . value . args . length === 1 &&
514
506
instr . value . args [ 0 ] . kind === 'Identifier'
515
507
) {
516
- const propSources = derivedTuple . get (
508
+ const invalidDeps = derivedTuple . get (
517
509
instr . value . args [ 0 ] . identifier . id ,
518
510
) ;
519
511
520
- if ( propSources !== undefined ) {
512
+ if ( invalidDeps !== undefined ) {
521
513
setStateCallsInEffect . push ( {
522
514
loc : instr . value . callee . loc ,
523
515
setStateId : instr . value . callee . identifier . id ,
524
- invalidDeps : new Map ( [
525
- [ instr . value . args [ 0 ] . identifier , propSources . sources ] ,
526
- ] ) ,
527
- } ) ;
528
- } else {
529
- setStateCallsInEffect . push ( {
530
- loc : instr . value . callee . loc ,
531
- setStateId : instr . value . callee . identifier . id ,
532
- invalidDeps : undefined ,
516
+ invalidDeps : invalidDeps ,
533
517
} ) ;
534
518
}
535
519
}
@@ -551,34 +535,33 @@ function validateEffect(
551
535
}
552
536
553
537
for ( const call of setStateCallsInEffect ) {
554
- if ( call . invalidDeps != null ) {
555
- let propNames = '' ;
556
- for ( const [ , places ] of call . invalidDeps . entries ( ) ) {
557
- const placeNames = places
558
- . map ( place => place . identifier . name ?. value )
559
- . join ( ', ' ) ;
560
- propNames += `[${ placeNames } ], ` ;
561
- }
562
- propNames = propNames . slice ( 0 , - 2 ) ;
563
- const propInfo = propNames ? ` (from props '${ propNames } ')` : '' ;
564
-
565
- errors . push ( {
566
- errorType : 'HoistState' ,
567
- propInfo : propInfo ,
568
- localStateInfo : undefined ,
569
- loc : call . loc ,
570
- setStateName :
571
- call . loc !== GeneratedSource ? call . loc . identifierName : undefined ,
572
- } ) ;
573
- } else {
574
- errors . push ( {
575
- errorType : 'CalculateInRender' ,
576
- propInfo : undefined ,
577
- localStateInfo : undefined ,
578
- loc : call . loc ,
579
- setStateName :
580
- call . loc !== GeneratedSource ? call . loc . identifierName : undefined ,
581
- } ) ;
538
+ const placeNames = call . invalidDeps . sources
539
+ . map ( place => place . identifier . name ?. value )
540
+ . join ( ', ' ) ;
541
+
542
+ let sourceNames = '' ;
543
+ let invalidDepInfo = '' ;
544
+ console . log ( call . invalidDeps ) ;
545
+ if ( call . invalidDeps . typeOfValue === 'fromProps' ) {
546
+ sourceNames += `[${ placeNames } ], ` ;
547
+ sourceNames = sourceNames . slice ( 0 , - 2 ) ;
548
+ invalidDepInfo = sourceNames
549
+ ? `Invalid deps from props ${ sourceNames } `
550
+ : '' ;
551
+ } else if ( call . invalidDeps . typeOfValue === 'fromState' ) {
552
+ sourceNames += `[${ placeNames } ], ` ;
553
+ sourceNames = sourceNames . slice ( 0 , - 2 ) ;
554
+ invalidDepInfo = sourceNames
555
+ ? `Invalid deps from local state: ${ sourceNames } `
556
+ : '' ;
582
557
}
558
+
559
+ errors . push ( {
560
+ errorType : call . invalidDeps . typeOfValue ,
561
+ invalidDepInfo : invalidDepInfo ,
562
+ loc : call . loc ,
563
+ setStateName :
564
+ call . loc !== GeneratedSource ? call . loc . identifierName : undefined ,
565
+ } ) ;
583
566
}
584
567
}
0 commit comments