mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Feature: Add support to exhaustive-deps rule for any hook ending with Effect (#18580)
* Add test cases for support exhaustive deps ending in Effect * Apply the exhaustive deps lint rule to any hook ending with Effect * Add another test for supporting linting useXEffect hooks Co-authored-by: Aaron Pettengill <aaron.pettengill@echoman.com>
This commit is contained in:
co-authored by
Aaron Pettengill
parent
eab94403d7
commit
5ac9ca72df
@@ -357,6 +357,36 @@ const tests = {
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
code: normalizeIndent`
|
||||
function MyComponent(props) {
|
||||
useCustomHook(() => {
|
||||
console.log(props.foo);
|
||||
});
|
||||
}
|
||||
`,
|
||||
options: [{additionalHooks: 'useCustomHook'}],
|
||||
},
|
||||
{
|
||||
code: normalizeIndent`
|
||||
function MyComponent(props) {
|
||||
useCustomHook(() => {
|
||||
console.log(props.foo);
|
||||
}, [props.foo]);
|
||||
}
|
||||
`,
|
||||
options: [{additionalHooks: 'useCustomHook'}],
|
||||
},
|
||||
{
|
||||
code: normalizeIndent`
|
||||
function MyComponent(props) {
|
||||
useCustomHook(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
}
|
||||
`,
|
||||
options: [{additionalHooks: 'useAnotherHook'}],
|
||||
},
|
||||
{
|
||||
code: normalizeIndent`
|
||||
function MyComponent(props) {
|
||||
@@ -365,7 +395,6 @@ const tests = {
|
||||
});
|
||||
}
|
||||
`,
|
||||
options: [{additionalHooks: 'useCustomEffect'}],
|
||||
},
|
||||
{
|
||||
code: normalizeIndent`
|
||||
@@ -375,17 +404,6 @@ const tests = {
|
||||
}, [props.foo]);
|
||||
}
|
||||
`,
|
||||
options: [{additionalHooks: 'useCustomEffect'}],
|
||||
},
|
||||
{
|
||||
code: normalizeIndent`
|
||||
function MyComponent(props) {
|
||||
useCustomEffect(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
}
|
||||
`,
|
||||
options: [{additionalHooks: 'useAnotherEffect'}],
|
||||
},
|
||||
{
|
||||
// Valid because we don't care about hooks outside of components.
|
||||
@@ -3002,6 +3020,105 @@ const tests = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: normalizeIndent`
|
||||
function MyComponent(props) {
|
||||
useCustomHook(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
React.useEffect(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
React.useCustomHook(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
}
|
||||
`,
|
||||
options: [{additionalHooks: 'useCustomHook'}],
|
||||
errors: [
|
||||
{
|
||||
message:
|
||||
"React Hook useCustomHook has a missing dependency: 'props.foo'. " +
|
||||
'Either include it or remove the dependency array.',
|
||||
suggestions: [
|
||||
{
|
||||
desc: 'Update the dependencies array to be: [props.foo]',
|
||||
output: normalizeIndent`
|
||||
function MyComponent(props) {
|
||||
useCustomHook(() => {
|
||||
console.log(props.foo);
|
||||
}, [props.foo]);
|
||||
useEffect(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
React.useEffect(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
React.useCustomHook(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
message:
|
||||
"React Hook useEffect has a missing dependency: 'props.foo'. " +
|
||||
'Either include it or remove the dependency array.',
|
||||
suggestions: [
|
||||
{
|
||||
desc: 'Update the dependencies array to be: [props.foo]',
|
||||
output: normalizeIndent`
|
||||
function MyComponent(props) {
|
||||
useCustomHook(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
console.log(props.foo);
|
||||
}, [props.foo]);
|
||||
React.useEffect(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
React.useCustomHook(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
message:
|
||||
"React Hook React.useEffect has a missing dependency: 'props.foo'. " +
|
||||
'Either include it or remove the dependency array.',
|
||||
suggestions: [
|
||||
{
|
||||
desc: 'Update the dependencies array to be: [props.foo]',
|
||||
output: normalizeIndent`
|
||||
function MyComponent(props) {
|
||||
useCustomHook(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
React.useEffect(() => {
|
||||
console.log(props.foo);
|
||||
}, [props.foo]);
|
||||
React.useCustomHook(() => {
|
||||
console.log(props.foo);
|
||||
}, []);
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: normalizeIndent`
|
||||
function MyComponent(props) {
|
||||
@@ -3019,7 +3136,6 @@ const tests = {
|
||||
}, []);
|
||||
}
|
||||
`,
|
||||
options: [{additionalHooks: 'useCustomEffect'}],
|
||||
errors: [
|
||||
{
|
||||
message:
|
||||
@@ -4054,6 +4170,36 @@ const tests = {
|
||||
],
|
||||
options: [{additionalHooks: 'useLayoutEffect_SAFE_FOR_SSR'}],
|
||||
},
|
||||
{
|
||||
code: `
|
||||
function MyComponent() {
|
||||
const myRef = useRef();
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
const handleMove = () => {};
|
||||
myRef.current.addEventListener('mousemove', handleMove);
|
||||
return () => myRef.current.removeEventListener('mousemove', handleMove);
|
||||
});
|
||||
return <div ref={myRef} />;
|
||||
}
|
||||
`,
|
||||
output: `
|
||||
function MyComponent() {
|
||||
const myRef = useRef();
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
const handleMove = () => {};
|
||||
myRef.current.addEventListener('mousemove', handleMove);
|
||||
return () => myRef.current.removeEventListener('mousemove', handleMove);
|
||||
});
|
||||
return <div ref={myRef} />;
|
||||
}
|
||||
`,
|
||||
errors: [
|
||||
`The ref value 'myRef.current' will likely have changed by the time ` +
|
||||
`this effect cleanup function runs. If this ref points to a node ` +
|
||||
`rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
|
||||
`and use that variable in the cleanup function.`,
|
||||
],
|
||||
},
|
||||
{
|
||||
// Autofix ignores constant primitives (leaving the ones that are there).
|
||||
code: normalizeIndent`
|
||||
|
||||
@@ -1504,7 +1504,9 @@ function getReactiveHookCallbackIndex(calleeNode, options) {
|
||||
// useImperativeHandle(ref, fn)
|
||||
return 1;
|
||||
default:
|
||||
if (node === calleeNode && options && options.additionalHooks) {
|
||||
if (node === calleeNode && node.name.match(/use.+Effect/)) {
|
||||
return 0;
|
||||
} else if (node === calleeNode && options && options.additionalHooks) {
|
||||
// Allow the user to provide a regular expression which enables the lint to
|
||||
// target custom reactive hooks.
|
||||
let name;
|
||||
|
||||
Reference in New Issue
Block a user