如何让React将自定义hook的返回值视为稳定身份?

Tao*_*hen 7 reactjs eslint react-hooks

在react文档中,我们可以发现:

\n
\n

笔记

\n

React 保证 setState 函数身份是稳定的,并且在重新渲染时不会改变。这就是为什么从 useEffect 或 useCallback 依赖项列表中省略它\xe2\x80\x99 是安全的。

\n
\n

有时候,自定义hook也能保证返回的函数身份稳定,是否可以让react知道呢?

\n
\n

与Jayce444讨论后添加:

\n

如果react不将自定义hook的返回值视为稳定身份,但我们将其从其他hook的依赖列表中省略,npm将报告警告

\n

Fan*_*ohn 2

考虑到您想要静默react-hooks/exhaustive-deps特定名称的 eslint 规则,我为该规则编写了一个补丁,它允许我使用以下配置:

'react-hooks/exhaustive-deps': [
  'warn',
  {
    stableHooksPattern: 'useDispatch|useSharedValue|useErrorDropdown',
    ignoredDepsPattern: '^navigation|navigate|popToTop|pop$',
  },
],
Run Code Online (Sandbox Code Playgroud)

这基本上导致以下钩子调用是“干净的”:

const navigation = useNavigation();

useEffect(() => {
  navigation.navigate('Voila');
}, []);
Run Code Online (Sandbox Code Playgroud)

这是我的补丁的源代码eslint-plugin-react-hooks@4.3.0

diff --git a/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js b/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js
index 29fb123..b22bc3f 100644
--- a/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js
+++ b/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js
@@ -735,6 +735,12 @@ var ExhaustiveDeps = {
         },
         enableDangerousAutofixThisMayCauseInfiniteLoops: {
           type: 'boolean'
+        },
+        stableHooksPattern: {
+          type: 'string'
+        },
+        ignoredDepsPattern: {
+          type: 'string'
         }
       }
     }]
@@ -743,9 +749,13 @@ var ExhaustiveDeps = {
     // Parse the `additionalHooks` regex.
     var additionalHooks = context.options && context.options[0] && context.options[0].additionalHooks ? new RegExp(context.options[0].additionalHooks) : undefined;
     var enableDangerousAutofixThisMayCauseInfiniteLoops = context.options && context.options[0] && context.options[0].enableDangerousAutofixThisMayCauseInfiniteLoops || false;
+    var stableHooksPattern = context.options && context.options[0] && context.options[0].stableHooksPattern ? new RegExp(context.options[0].stableHooksPattern) : undefined;
+    var ignoredDepsPattern = context.options && context.options[0] && context.options[0].ignoredDepsPattern ? new RegExp(context.options[0].ignoredDepsPattern) : undefined;
     var options = {
       additionalHooks: additionalHooks,
-      enableDangerousAutofixThisMayCauseInfiniteLoops: enableDangerousAutofixThisMayCauseInfiniteLoops
+      enableDangerousAutofixThisMayCauseInfiniteLoops: enableDangerousAutofixThisMayCauseInfiniteLoops,
+      stableHooksPattern: stableHooksPattern,
+      ignoredDepsPattern: ignoredDepsPattern
     };
 
     function reportProblem(problem) {
@@ -904,7 +914,9 @@ var ExhaustiveDeps = {
         var _callee = callee,
             name = _callee.name;
 
-        if (name === 'useRef' && id.type === 'Identifier') {
+        if (options.stableHooksPattern && options.stableHooksPattern.test(name)) {
+          return true;
+        } else if (name === 'useRef' && id.type === 'Identifier') {
           // useRef() return value is stable.
           return true;
         } else if (name === 'useState' || name === 'useReducer') {
@@ -1098,7 +1110,7 @@ var ExhaustiveDeps = {
 
             if (!dependencies.has(dependency)) {
               var resolved = reference.resolved;
-              var isStable = memoizedIsStablecKnownHookValue(resolved) || memoizedIsFunctionWithoutCapturedValues(resolved);
+              var isStable = memoizedIsStablecKnownHookValue(resolved) || memoizedIsFunctionWithoutCapturedValues(resolved) || (options.ignoredDepsPattern && options.ignoredDepsPattern.test(resolved.name));
               dependencies.set(dependency, {
                 isStable: isStable,
                 references: [reference]
Run Code Online (Sandbox Code Playgroud)

补丁的文件名是eslint-plugin-react-hooks+4.3.0.patch,您应该将其放入patches存储库根目录中。

免责声明:这仅适用于全球。因此,如果您想将返回值声明为“稳定”,则必须将其列在 eslint 配置中,并且它将在您的项目中全局生效。

如果您希望能够将返回值“标记”为稳定,则需要进一步修改该 eslint 插件以使其正常工作。不幸的是,我没有时间。