Skip to content

Commit 81867c4

Browse files
committed
fix(linter): fix stack overflow in react/exhaustive deps (#10322)
fixes #10319
1 parent a95ba40 commit 81867c4

File tree

2 files changed

+45
-10
lines changed

2 files changed

+45
-10
lines changed

crates/oxc_linter/src/rules/react/exhaustive_deps.rs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -855,14 +855,21 @@ fn is_stable_value<'a, 'b>(
855855

856856
{
857857
// if the variables is a function, check whether the function is stable
858-
let function_body: Option<&oxc_allocator::Box<'_, FunctionBody<'_>>> =
859-
match init.get_inner_expression() {
860-
Expression::ArrowFunctionExpression(arrow_func) => Some(&arrow_func.body),
861-
Expression::FunctionExpression(func) => func.body.as_ref(),
862-
_ => None,
863-
};
858+
let function_body = match init.get_inner_expression() {
859+
Expression::ArrowFunctionExpression(arrow_func) => Some(&arrow_func.body),
860+
Expression::FunctionExpression(func) => func.body.as_ref(),
861+
_ => None,
862+
};
864863
if let Some(function_body) = function_body {
865-
return is_function_stable(function_body, ctx, component_scope_id);
864+
return is_function_stable(
865+
function_body,
866+
declaration
867+
.id
868+
.get_binding_identifier()
869+
.map(oxc_ast::ast::BindingIdentifier::symbol_id),
870+
ctx,
871+
component_scope_id,
872+
);
866873
}
867874
}
868875

@@ -935,14 +942,15 @@ fn is_stable_value<'a, 'b>(
935942

936943
let Some(function_body) = function_body else { return false };
937944

938-
is_function_stable(function_body, ctx, component_scope_id)
945+
is_function_stable(function_body, None, ctx, component_scope_id)
939946
}
940947
_ => false,
941948
}
942949
}
943950

944951
fn is_function_stable<'a, 'b>(
945952
function_body: &'b FunctionBody<'a>,
953+
function_symbol_id: Option<SymbolId>,
946954
ctx: &'b LintContext<'a>,
947955
component_scope_id: ScopeId,
948956
) -> bool {
@@ -952,8 +960,10 @@ fn is_function_stable<'a, 'b>(
952960
collector.found_dependencies
953961
};
954962

955-
deps.iter()
956-
.all(|dep| !is_identifier_a_dependency(dep.name, dep.reference_id, ctx, component_scope_id))
963+
deps.iter().all(|dep| {
964+
dep.symbol_id.zip(function_symbol_id).is_none_or(|(l, r)| l != r)
965+
&& !is_identifier_a_dependency(dep.name, dep.reference_id, ctx, component_scope_id)
966+
})
957967
}
958968

959969
// https://github.com/facebook/react/blob/fee786a057774ab687aff765345dd86fce534ab2/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js#L1742
@@ -3539,6 +3549,22 @@ fn test() {
35393549
console.log(foo);
35403550
}, [foo]);
35413551
}",
3552+
// https://github.com/oxc-project/oxc/issues/10319
3553+
r"import { useEffect } from 'react'
3554+
3555+
export const Test = () => {
3556+
const handleFrame = () => {
3557+
setTimeout(handleFrame)
3558+
}
3559+
3560+
useEffect(() => {
3561+
setTimeout(handleFrame)
3562+
}, [])
3563+
3564+
return (
3565+
<></>
3566+
)
3567+
}",
35423568
];
35433569

35443570
Tester::new(ExhaustiveDeps::NAME, ExhaustiveDeps::PLUGIN, pass, fail).test_and_snapshot();

crates/oxc_linter/src/snapshots/react_exhaustive_deps.snap

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2239,3 +2239,12 @@ source: crates/oxc_linter/src/tester.rs
22392239
9 │ }
22402240
╰────
22412241
help: Try memoizing this variable with `useRef` or `useCallback`.
2242+
2243+
eslint-plugin-react-hooks(exhaustive-deps): React Hook useEffect has a missing dependency: 'handleFrame'
2244+
╭─[exhaustive_deps.tsx:10:14]
2245+
9setTimeout(handleFrame)
2246+
10 │ }, [])
2247+
· ──
2248+
11
2249+
╰────
2250+
help: Either include it or remove the dependency array.

0 commit comments

Comments
 (0)