main
js 167 lines 4.09 KB
Raw
1 /**
2 * Exhaustive Deps
3 */
4 // Valid because dependencies are declared correctly
5 function Comment({comment, commentSource}) {
6 const currentUserID = comment.viewer.id;
7 const environment = RelayEnvironment.forUser(currentUserID);
8 const commentID = nullthrows(comment.id);
9 useEffect(() => {
10 const subscription = SubscriptionCounter.subscribeOnce(
11 `StoreSubscription_${commentID}`,
12 () =>
13 StoreSubscription.subscribe(
14 environment,
15 {
16 comment_id: commentID,
17 },
18 currentUserID,
19 commentSource
20 )
21 );
22 return () => subscription.dispose();
23 }, [commentID, commentSource, currentUserID, environment]);
24 }
25
26 // Valid because no dependencies
27 function UseEffectWithNoDependencies() {
28 const local = {};
29 useEffect(() => {
30 console.log(local);
31 });
32 }
33 function UseEffectWithEmptyDependencies() {
34 useEffect(() => {
35 const local = {};
36 console.log(local);
37 }, []);
38 }
39
40 // OK because `props` wasn't defined.
41 function ComponentWithNoPropsDefined() {
42 useEffect(() => {
43 console.log(props.foo);
44 }, []);
45 }
46
47 // Valid because props are declared as a dependency
48 function ComponentWithPropsDeclaredAsDep({foo}) {
49 useEffect(() => {
50 console.log(foo.length);
51 console.log(foo.slice(0));
52 }, [foo]);
53 }
54
55 // Valid because individual props are declared as dependencies
56 function ComponentWithIndividualPropsDeclaredAsDeps(props) {
57 useEffect(() => {
58 console.log(props.foo);
59 console.log(props.bar);
60 }, [props.bar, props.foo]);
61 }
62
63 // Invalid because neither props or props.foo are declared as dependencies
64 function ComponentWithoutDeclaringPropAsDep(props) {
65 useEffect(() => {
66 console.log(props.foo);
67 // eslint-disable-next-line react-hooks/exhaustive-deps
68 }, []);
69 useCallback(() => {
70 console.log(props.foo);
71 // eslint-disable-next-line react-hooks/exhaustive-deps
72 }, []);
73 useMemo(() => {
74 console.log(props.foo);
75 // eslint-disable-next-line react-hooks/exhaustive-deps
76 }, []);
77 React.useEffect(() => {
78 console.log(props.foo);
79 // eslint-disable-next-line react-hooks/exhaustive-deps
80 }, []);
81 React.useCallback(() => {
82 console.log(props.foo);
83 // eslint-disable-next-line react-hooks/exhaustive-deps
84 }, []);
85 React.useMemo(() => {
86 console.log(props.foo);
87 // eslint-disable-next-line react-hooks/exhaustive-deps
88 }, []);
89 React.notReactiveHook(() => {
90 console.log(props.foo);
91 }, []); // This one isn't a violation
92 }
93
94 /**
95 * Rules of Hooks
96 */
97 // Valid because functions can call functions.
98 function normalFunctionWithConditionalFunction() {
99 if (cond) {
100 doSomething();
101 }
102 }
103
104 // Valid because hooks can call hooks.
105 function useHook() {
106 useState();
107 }
108 const whatever = function useHook() {
109 useState();
110 };
111 const useHook1 = () => {
112 useState();
113 };
114 let useHook2 = () => useState();
115 useHook2 = () => {
116 useState();
117 };
118
119 // Invalid because hooks can't be called in conditionals.
120 function ComponentWithConditionalHook() {
121 if (cond) {
122 // eslint-disable-next-line react-hooks/rules-of-hooks
123 useConditionalHook();
124 }
125 }
126
127 // Invalid because hooks can't be called in loops.
128 function useHookInLoops() {
129 while (a) {
130 // eslint-disable-next-line react-hooks/rules-of-hooks
131 useHook1();
132 if (b) return;
133 // eslint-disable-next-line react-hooks/rules-of-hooks
134 useHook2();
135 }
136 while (c) {
137 // eslint-disable-next-line react-hooks/rules-of-hooks
138 useHook3();
139 if (d) return;
140 // eslint-disable-next-line react-hooks/rules-of-hooks
141 useHook4();
142 }
143 }
144
145 /**
146 * Compiler Rules
147 */
148 // Invalid: component factory
149 function InvalidComponentFactory() {
150 const DynamicComponent = () => <div>Hello</div>;
151 // eslint-disable-next-line react-hooks/static-components
152 return <DynamicComponent />;
153 }
154
155 // Invalid: mutating globals
156 function InvalidGlobals() {
157 // eslint-disable-next-line react-hooks/immutability
158 window.myGlobal = 42;
159 return <div>Done</div>;
160 }
161
162 // Invalid: useMemo with wrong deps
163 function InvalidUseMemo({items}) {
164 // eslint-disable-next-line react-hooks/exhaustive-deps
165 const sorted = useMemo(() => [...items].sort(), []);
166 return <div>{sorted.length}</div>;
167 }