Skip to content

Commit 67fd550

Browse files
committed
More doc updates
1 parent 9d35ad6 commit 67fd550

File tree

1 file changed

+34
-15
lines changed

1 file changed

+34
-15
lines changed

crates/biome_js_analyze/src/lint/correctness/use_exhaustive_dependencies.rs

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,16 @@ use crate::react::hooks::*;
2626
use crate::services::semantic::Semantic;
2727

2828
declare_lint_rule! {
29-
/// Enforce all dependencies are correctly specified in a React hook.
29+
/// Enforce correct dependency usage within React hooks.
3030
///
3131
/// React components have access to various [hooks](https://react.dev/reference/react/hooks) that can perform
3232
/// various actions like querying and updating state.
33-
/// However, incorrectly specifying dependencies for a hook can lead to "stale closures" where old versions of state variables
34-
/// are used for subsequent page renders.
3533
///
36-
/// This rule attempts to prevent such issues by diagnosing potentially incorrect usages of hook dependencies.
34+
/// Notably, React is **unable** to capture changes to variables not included inside a hook's dependency array, resulting in
35+
/// any such references being "locked" to their initial values even if updated later.
36+
/// Such "stale closures" are a common pitfall among React developers.
37+
///
38+
/// This rule attempts to prevent such issues by diagnosing potentially incorrect or invalid usages of hook dependencies.
3739
///
3840
/// By default, the rule will inspect the following built-in React hooks (as well as their Preact counterparts):
3941
///
@@ -67,14 +69,26 @@ declare_lint_rule! {
6769
/// }, []);
6870
/// }
6971
/// ```
72+
///
73+
/// ```js,expect_diagnostic
74+
/// import { useEffect } from "react";
75+
///
76+
/// function badComponent() {
77+
/// let a = 1;
78+
/// useEffect(() => {
79+
/// console.log(a);
80+
/// }, "not an array");
81+
/// }
82+
/// ```
83+
///
7084
///
7185
/// ```js,expect_diagnostic
7286
/// import { useEffect } from "react";
7387
///
7488
/// function component() {
75-
/// let b = 1;
89+
/// let unused = 1;
7690
/// useEffect(() => {
77-
/// }, [b]);
91+
/// }, [unused]);
7892
/// }
7993
/// ```
8094
///
@@ -85,7 +99,7 @@ declare_lint_rule! {
8599
/// const [name, setName] = useState();
86100
/// useEffect(() => {
87101
/// console.log(name);
88-
/// setName("");
102+
/// setName("shouldn't need to be here");
89103
/// }, [name, setName]);
90104
/// }
91105
/// ```
@@ -121,6 +135,7 @@ declare_lint_rule! {
121135
/// function component() {
122136
/// const a = 1;
123137
/// useEffect(() => {
138+
/// // a is const here, so there is no mutable state to change
124139
/// console.log(a);
125140
/// });
126141
/// }
@@ -199,8 +214,8 @@ declare_lint_rule! {
199214
/// {
200215
/// "options": {
201216
/// "hooks": [
202-
/// { "name": "useLocation", "closureIndex": 0, "dependenciesIndex": 1},
203-
/// { "name": "useQuery", "closureIndex": 1, "dependenciesIndex": 0}
217+
/// { "name": "useLocation", "closureIndex": 0, "dependenciesIndex": 1 },
218+
/// { "name": "useQuery", "closureIndex": 1, "dependenciesIndex": 0 }
204219
/// ]
205220
/// }
206221
/// }
@@ -251,7 +266,7 @@ declare_lint_rule! {
251266
///
252267
/// ```js,use_options
253268
/// const dispatch = useDispatch();
254-
/// // No need to list `dispatch` as dependency if it doesn't change
269+
/// // No need to list `dispatch` as dependency since it doesn't change
255270
/// const doAction = useCallback(() => dispatch(someAction()), []);
256271
/// ```
257272
///
@@ -274,7 +289,7 @@ declare_lint_rule! {
274289
/// ```jsx,use_options
275290
/// function Foo() {
276291
/// let stateVar = 1;
277-
/// // not used but still OK
292+
/// // not used but still OK due to disabled rule
278293
/// useEffect(() => {}, [stateVar]);
279294
/// }
280295
/// ```
@@ -297,7 +312,7 @@ declare_lint_rule! {
297312
/// ```
298313
///
299314
/// ```jsx,use_options,expect_diagnostic
300-
/// function Foo() {
315+
/// function NoArrayYesProblem() {
301316
/// let stateVar = 1;
302317
/// useEffect(() => {});
303318
/// }
@@ -919,7 +934,7 @@ impl Rule for UseExhaustiveDependencies {
919934
} => Some(RuleDiagnostic::new(
920935
rule_category!(),
921936
function_name_range,
922-
markup! {"This hook does not have a dependencies array"},
937+
markup! {"This hook does not have a dependencies array."},
923938
)),
924939
Fix::NonLiteralDependenciesArray { expr } => Some(
925940
RuleDiagnostic::new(
@@ -940,7 +955,11 @@ impl Rule for UseExhaustiveDependencies {
940955
let mut diag = RuleDiagnostic::new(
941956
rule_category!(),
942957
function_name_range,
943-
markup! {"This hook does not specify its dependency on "<Emphasis>{capture_text.as_ref()}</Emphasis>"."},
958+
markup! {
959+
"This hook "<Emphasis>"does not specify"</Emphasis>" its dependency on "<Emphasis>{capture_text.as_ref()}</Emphasis>"."
960+
"\nReact is unable to capture changes to variables not included inside hook dependencies, resulting in"<Emphasis>"outdated references"</Emphasis>"
961+
"\nthat can produce unexpected results."
962+
},
944963
);
945964

946965
for range in captures_range {
@@ -1024,7 +1043,7 @@ impl Rule for UseExhaustiveDependencies {
10241043
rule_category!(),
10251044
function_name_range,
10261045
markup! {
1027-
"This hook specifies a dependency more specific that its captures: "{dependency_text.as_ref()}""
1046+
"This hook specifies a dependency more specific than its captures: "{dependency_text.as_ref()}""
10281047
},
10291048
)
10301049
.detail(capture_range, "This capture is more generic than...")

0 commit comments

Comments
 (0)