@@ -103,6 +103,25 @@ new MyRuleTester().run("no-derived-state", rule, {
103103 }
104104 ` ,
105105 } ,
106+ {
107+ // https://github.com/NickvanDyke/eslint-plugin-react-you-might-not-need-an-effect/issues/35
108+ // While it *could* be an anti-pattern or unnecessary, effects *are* meant to synchronize systems.
109+ // So we guess that a "subscription effect" is usually valid, or may be more readable.
110+ name : "Synchronize internal state" ,
111+ code : js `
112+ function Component() {
113+ const [name, setName] = useState();
114+ const [model] = useState(
115+ () => new FormModel(props)
116+ );
117+
118+ useEffect(() => {
119+ model.setFieldDescriptor(name);
120+ return () => model.removeField(name);
121+ }, [model, name]);
122+ }
123+ ` ,
124+ } ,
106125 {
107126 name : "Subscribe to external state" ,
108127 code : js `
@@ -390,53 +409,6 @@ new MyRuleTester().run("no-derived-state", rule, {
390409 }
391410 ` ,
392411 } ,
393- {
394- // https://github.com/NickvanDyke/eslint-plugin-react-you-might-not-need-an-effect/issues/35
395- // TODO: Finally time to not consider state MemberExpressions as state setters
396- todo : true ,
397- name : "Calling method on state" ,
398- code : js `
399- function Component() {
400- const [name, setName] = useState();
401- const [model] = useState(
402- () => new FormModel(props)
403- );
404-
405- // Register field within the model
406- useEffect(() => {
407- model.setFieldDescriptor(name);
408- }, [model, name]);
409- }
410- ` ,
411- } ,
412- {
413- // https://github.com/NickvanDyke/eslint-plugin-react-you-might-not-need-an-effect/issues/35
414- name : "Cleanup function calls method on state" ,
415- code : js `
416- function Component() {
417- const [name, setName] = useState();
418- const [model] = useState(
419- () => new FormModel(props)
420- );
421-
422- useEffect(() => {
423- return () => model.removeField(name);
424- }, [model, name]);
425- }
426- ` ,
427- } ,
428- {
429- // TODO: Double-check whether this is valid; compared to calling a method on state
430- name : "Cleanup function sets state" ,
431- code : js `
432- function Component() {
433- const [isMounted, setIsMounted] = useState(true);
434- useEffect(() => {
435- return () => setIsMounted(false);
436- }, []);
437- }
438- ` ,
439- } ,
440412 ] ,
441413 invalid : [
442414 {
@@ -518,7 +490,7 @@ new MyRuleTester().run("no-derived-state", rule, {
518490 ] ,
519491 } ,
520492 {
521- name : "From derived prop" ,
493+ name : "From intermediate prop" ,
522494 code : js `
523495 function Form({ firstName, lastName }) {
524496 const [fullName, setFullName] = useState('');
@@ -537,7 +509,7 @@ new MyRuleTester().run("no-derived-state", rule, {
537509 ] ,
538510 } ,
539511 {
540- name : "From props via member function " ,
512+ name : "From props via method " ,
541513 code : js `
542514 function DoubleList({ list }) {
543515 const [doubleList, setDoubleList] = useState([]);
@@ -555,8 +527,7 @@ new MyRuleTester().run("no-derived-state", rule, {
555527 ] ,
556528 } ,
557529 {
558- name : "From internal state via member function" ,
559- todo : true ,
530+ name : "From internal state via method" ,
560531 code : js `
561532 function DoubleList() {
562533 const [list, setList] = useState([]);
@@ -572,6 +543,12 @@ new MyRuleTester().run("no-derived-state", rule, {
572543 messageId : "avoidDerivedState" ,
573544 data : { state : "doubleList" } ,
574545 } ,
546+ // TODO: Kinda confusing to double-flag... ideally we'd ignore the `concat` call, given it's a setter arg.
547+ // Or even a different error message/rule for `no-mutate-state`...? If we can find a good heuristic.
548+ {
549+ messageId : "avoidDerivedState" ,
550+ data : { state : "list" } ,
551+ } ,
575552 ] ,
576553 } ,
577554 {
0 commit comments