From 216b39c04b5e064494b805e58b436ffcf8ee18b1 Mon Sep 17 00:00:00 2001 From: msdlisper <1170167213@qq.com> Date: Sat, 28 Oct 2023 21:40:16 +0800 Subject: [PATCH 1/2] fix: bug with useContext/useSyncExternalStore (#609) --- .../use_exhaustive_dependencies.rs | 3 -- .../useExhaustiveDependencies/valid.js | 13 +++++-- .../useExhaustiveDependencies/valid.js.snap | 14 ++++++-- .../rules/use-exhaustive-dependencies.md | 35 +++++++++---------- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/crates/biome_js_analyze/src/semantic_analyzers/correctness/use_exhaustive_dependencies.rs b/crates/biome_js_analyze/src/semantic_analyzers/correctness/use_exhaustive_dependencies.rs index bf6f368ffb96..f7de9dc08021 100644 --- a/crates/biome_js_analyze/src/semantic_analyzers/correctness/use_exhaustive_dependencies.rs +++ b/crates/biome_js_analyze/src/semantic_analyzers/correctness/use_exhaustive_dependencies.rs @@ -207,9 +207,6 @@ impl Default for ReactExtensiveDependenciesOptions { StableReactHookConfiguration::new("useReducer", Some(1)), StableReactHookConfiguration::new("useTransition", Some(1)), StableReactHookConfiguration::new("useRef", None), - StableReactHookConfiguration::new("useContext", None), - StableReactHookConfiguration::new("useId", None), - StableReactHookConfiguration::new("useSyncExternalStore", None), ]); Self { diff --git a/crates/biome_js_analyze/tests/specs/correctness/useExhaustiveDependencies/valid.js b/crates/biome_js_analyze/tests/specs/correctness/useExhaustiveDependencies/valid.js index 5c84dd763152..9574877a4de8 100644 --- a/crates/biome_js_analyze/tests/specs/correctness/useExhaustiveDependencies/valid.js +++ b/crates/biome_js_analyze/tests/specs/correctness/useExhaustiveDependencies/valid.js @@ -1,7 +1,7 @@ /* should not generate diagnostics */ import React from "react"; -import { useEffect } from "react"; +import { useEffect, useSyncExternalStore } from "react"; import doSomething from 'a'; // No captures @@ -62,7 +62,7 @@ function MyComponent4() { console.log(id); console.log(externalStore); - }, [name, state, memoizedCallback, memoizedValue, isPending]); + }, [name, state, memoizedCallback, memoizedValue, isPending, externalStore, id, theme]); } // all hooks with dependencies @@ -167,3 +167,12 @@ function MyComponent16() { console.log(a); }, [a]); } + +// https://github.com/biomejs/biome/issues/609 +function MyComponent17() { + const data = useSyncExternalStore(subscribe, getSnapshot); + + useEffect(() => { + console.log(data); + }, [data]); +} diff --git a/crates/biome_js_analyze/tests/specs/correctness/useExhaustiveDependencies/valid.js.snap b/crates/biome_js_analyze/tests/specs/correctness/useExhaustiveDependencies/valid.js.snap index 5171784a7ea9..3a31d3b0c001 100644 --- a/crates/biome_js_analyze/tests/specs/correctness/useExhaustiveDependencies/valid.js.snap +++ b/crates/biome_js_analyze/tests/specs/correctness/useExhaustiveDependencies/valid.js.snap @@ -1,5 +1,6 @@ --- source: crates/biome_js_analyze/tests/spec_tests.rs +assertion_line: 83 expression: valid.js --- # Input @@ -7,7 +8,7 @@ expression: valid.js /* should not generate diagnostics */ import React from "react"; -import { useEffect } from "react"; +import { useEffect, useSyncExternalStore } from "react"; import doSomething from 'a'; // No captures @@ -68,7 +69,7 @@ function MyComponent4() { console.log(id); console.log(externalStore); - }, [name, state, memoizedCallback, memoizedValue, isPending]); + }, [name, state, memoizedCallback, memoizedValue, isPending, externalStore, id, theme]); } // all hooks with dependencies @@ -174,6 +175,15 @@ function MyComponent16() { }, [a]); } +// https://github.com/biomejs/biome/issues/609 +function MyComponent17() { + const data = useSyncExternalStore(subscribe, getSnapshot); + + useEffect(() => { + console.log(data); + }, [data]); +} + ``` diff --git a/website/src/content/docs/linter/rules/use-exhaustive-dependencies.md b/website/src/content/docs/linter/rules/use-exhaustive-dependencies.md index 0e30387ccba4..7d85f57acf40 100644 --- a/website/src/content/docs/linter/rules/use-exhaustive-dependencies.md +++ b/website/src/content/docs/linter/rules/use-exhaustive-dependencies.md @@ -23,14 +23,11 @@ The rule will inspect the following **known** hooks: - `useMemo` - `useImperativeHandle` - `useState` -- `useContext` - `useReducer` - `useRef` - `useDebugValue` - `useDeferredValue` - `useTransition` -- `useId` -- `useSyncExternalStore` If you want to add more hooks to the rule, check the [#options](options). @@ -52,23 +49,23 @@ function component() {
correctness/useExhaustiveDependencies.js:5:5 lint/correctness/useExhaustiveDependencies ━━━━━━━━━━━━
 
    This hook does not specify all of its dependencies.
-  
+
     3 │ function component() {
     4 │     let a = 1;
   > 5 │     useEffect(() => {
        ^^^^^^^^^
     6 │         console.log(a);
     7 │     });
-  
+
    This dependency is not specified in the hook dependency list.
-  
+
     4 │     let a = 1;
     5 │     useEffect(() => {
   > 6 │         console.log(a);
                        ^
     7 │     });
     8 │ }
-  
+
 
```jsx @@ -84,23 +81,23 @@ function component() {
correctness/useExhaustiveDependencies.js:5:5 lint/correctness/useExhaustiveDependencies ━━━━━━━━━━━━
 
    This hook specifies more dependencies than necessary.
-  
+
     3 │ function component() {
     4 │     let b = 1;
   > 5 │     useEffect(() => {
        ^^^^^^^^^
     6 │     }, [b]);
     7 │ }
-  
+
    This dependency can be removed from the list.
-  
+
     4 │     let b = 1;
     5 │     useEffect(() => {
   > 6 │     }, [b]);
            ^
     7 │ }
     8 │ 
-  
+
 
```jsx @@ -118,23 +115,23 @@ function component() {
correctness/useExhaustiveDependencies.js:5:5 lint/correctness/useExhaustiveDependencies ━━━━━━━━━━━━
 
    This hook specifies more dependencies than necessary.
-  
+
     3 │ function component() {
     4 │     const [name, setName] = useState();
   > 5 │     useEffect(() => {
        ^^^^^^^^^
     6 │         console.log(name);
     7 │         setName("");
-  
+
    This dependency can be removed from the list.
-  
+
      6 │         console.log(name);
      7 │         setName("");
    > 8 │     }, [name, setName]);
                   ^^^^^^^
      9 │ }
     10 │ 
-  
+
 
```jsx @@ -152,23 +149,23 @@ function component() {
correctness/useExhaustiveDependencies.js:6:5 lint/correctness/useExhaustiveDependencies ━━━━━━━━━━━━
 
    This hook does not specify all of its dependencies.
-  
+
     4 │     let a = 1;
     5 │     const b = a + 1;
   > 6 │     useEffect(() => {
        ^^^^^^^^^
     7 │         console.log(b);
     8 │     });
-  
+
    This dependency is not specified in the hook dependency list.
-  
+
     5 │     const b = a + 1;
     6 │     useEffect(() => {
   > 7 │         console.log(b);
                        ^
     8 │     });
     9 │ }
-  
+
 
## Valid From 106c23f3bf2e703444cb5294bf7a2b7c3f3a676b Mon Sep 17 00:00:00 2001 From: msdlisper <1170167213@qq.com> Date: Sat, 28 Oct 2023 22:21:35 +0800 Subject: [PATCH 2/2] docs: update docs (#609) --- .../use_exhaustive_dependencies.rs | 9 ------ .../rules/use-exhaustive-dependencies.md | 32 +++++++++---------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/crates/biome_js_analyze/src/semantic_analyzers/correctness/use_exhaustive_dependencies.rs b/crates/biome_js_analyze/src/semantic_analyzers/correctness/use_exhaustive_dependencies.rs index f7de9dc08021..adb8c4b85d6a 100644 --- a/crates/biome_js_analyze/src/semantic_analyzers/correctness/use_exhaustive_dependencies.rs +++ b/crates/biome_js_analyze/src/semantic_analyzers/correctness/use_exhaustive_dependencies.rs @@ -36,14 +36,11 @@ declare_rule! { /// - `useMemo` /// - `useImperativeHandle` /// - `useState` - /// - `useContext` /// - `useReducer` /// - `useRef` /// - `useDebugValue` /// - `useDeferredValue` /// - `useTransition` - /// - `useId` - /// - `useSyncExternalStore` /// /// If you want to add more hooks to the rule, check the [#options](options). /// @@ -180,7 +177,6 @@ impl Default for ReactExtensiveDependenciesOptions { ("useMemo".to_string(), (0, 1).into()), ("useImperativeHandle".to_string(), (1, 2).into()), ("useState".to_string(), ReactHookConfiguration::default()), - ("useContext".to_string(), ReactHookConfiguration::default()), ("useReducer".to_string(), ReactHookConfiguration::default()), ("useRef".to_string(), ReactHookConfiguration::default()), ( @@ -195,11 +191,6 @@ impl Default for ReactExtensiveDependenciesOptions { "useTransition".to_string(), ReactHookConfiguration::default(), ), - ("useId".to_string(), ReactHookConfiguration::default()), - ( - "useSyncExternalStore".to_string(), - ReactHookConfiguration::default(), - ), ]); let stable_config = FxHashSet::from_iter([ diff --git a/website/src/content/docs/linter/rules/use-exhaustive-dependencies.md b/website/src/content/docs/linter/rules/use-exhaustive-dependencies.md index 7d85f57acf40..8df5e9fb8f87 100644 --- a/website/src/content/docs/linter/rules/use-exhaustive-dependencies.md +++ b/website/src/content/docs/linter/rules/use-exhaustive-dependencies.md @@ -49,23 +49,23 @@ function component() {
correctness/useExhaustiveDependencies.js:5:5 lint/correctness/useExhaustiveDependencies ━━━━━━━━━━━━
 
    This hook does not specify all of its dependencies.
-
+  
     3 │ function component() {
     4 │     let a = 1;
   > 5 │     useEffect(() => {
        ^^^^^^^^^
     6 │         console.log(a);
     7 │     });
-
+  
    This dependency is not specified in the hook dependency list.
-
+  
     4 │     let a = 1;
     5 │     useEffect(() => {
   > 6 │         console.log(a);
                        ^
     7 │     });
     8 │ }
-
+  
 
```jsx @@ -81,23 +81,23 @@ function component() {
correctness/useExhaustiveDependencies.js:5:5 lint/correctness/useExhaustiveDependencies ━━━━━━━━━━━━
 
    This hook specifies more dependencies than necessary.
-
+  
     3 │ function component() {
     4 │     let b = 1;
   > 5 │     useEffect(() => {
        ^^^^^^^^^
     6 │     }, [b]);
     7 │ }
-
+  
    This dependency can be removed from the list.
-
+  
     4 │     let b = 1;
     5 │     useEffect(() => {
   > 6 │     }, [b]);
            ^
     7 │ }
     8 │ 
-
+  
 
```jsx @@ -115,23 +115,23 @@ function component() {
correctness/useExhaustiveDependencies.js:5:5 lint/correctness/useExhaustiveDependencies ━━━━━━━━━━━━
 
    This hook specifies more dependencies than necessary.
-
+  
     3 │ function component() {
     4 │     const [name, setName] = useState();
   > 5 │     useEffect(() => {
        ^^^^^^^^^
     6 │         console.log(name);
     7 │         setName("");
-
+  
    This dependency can be removed from the list.
-
+  
      6 │         console.log(name);
      7 │         setName("");
    > 8 │     }, [name, setName]);
                   ^^^^^^^
      9 │ }
     10 │ 
-
+  
 
```jsx @@ -149,23 +149,23 @@ function component() {
correctness/useExhaustiveDependencies.js:6:5 lint/correctness/useExhaustiveDependencies ━━━━━━━━━━━━
 
    This hook does not specify all of its dependencies.
-
+  
     4 │     let a = 1;
     5 │     const b = a + 1;
   > 6 │     useEffect(() => {
        ^^^^^^^^^
     7 │         console.log(b);
     8 │     });
-
+  
    This dependency is not specified in the hook dependency list.
-
+  
     5 │     const b = a + 1;
     6 │     useEffect(() => {
   > 7 │         console.log(b);
                        ^
     8 │     });
     9 │ }
-
+  
 
## Valid