反应ESLint规则详尽-deps启用自定义钩子的deps数组警告

时间:2020-01-22 16:07:09

标签: reactjs react-hooks eslint

是否有一种方法可以告诉react-hooks/exhaustive-deps ESLint规则来警告我有关缺少deps的自定义钩子用法的信息?例如:

function useCustomHook(callback, deps) {
    ...
    useMemo(() => ..., deps);
    ...
}

// When using useCustomHook in a component:
function Component({ dep1, dep2, dep3 }) {
    const res = useCustomHook(
        () => dep1 + dep2 + dep3,
    []); // Even if this is a custom hook,
         // I would like exhaustive-deps to warn me
         // and tell me that I need to pass `dep1`, `dep2` and `dep3`
         // to the deps array...
    ...
}

另一个例子:

我有以下自定义钩子,可用于在功能性React组件中实现抽象工厂:

/**
 * Usage:
 * 
 *     const choice1 = {
 *         color: "red",
 *         label: "Fire"
 *     };
 * 
 *     const choice2 = {
 *         color: "green",
 *         label: "Grass"
 *     }
 * 
 *     const choice3 = {
 *         color: "blue",
 *         label: "Water"
 *     }
 *     
 *     const factory = useFactory(() => [
 *        [dep1, choice1],
 *        [dep2, choice2],
 *        [dep3, choice3]
 *     ], [dep1, dep2, dep3]);
 * 
 *     // Assuming dep1 = false, dep2 = true and dep3 = false:
 *     factory === choice2 // true
 */
export default function useFactory(tuplesFn, deps) {
  const tuples = useMemo(tuplesFn, deps);

  // "testConditionFn" is pure and does never change.
  const testConditionFn = useCallback(
    testCondition =>
      Boolean(
        typeof testCondition === "function" ? testCondition() : testCondition
      ),
    []
  );

  const factoryValue = useMemo(() => {
    let i = 0;
    // Loop through all the tuples except the last one (handled after this loop).
    for (; i < tuples.length - 1; i++) {
      const tuple = tuples[i];
      const [testCondition, factoryValue] = tuple;
      if (testConditionFn(testCondition)) {
        // Test condition for factory value is satisfied.
        return factoryValue;
      }
    }
    const lastTuple = tuples[i];
    if (isArray(lastTuple) && lastTuple.length === 2) {
      const [testCondition, factoryValue] = lastTuple;
      if (testConditionFn(testCondition)) {
        // Test condition for last factory value is satisfied.
        return factoryValue;
      }

      // No default and no factory value satisfying a test condition.
      return void 0;
    } else {
      // Default factory value.
      return lastTuple;
    }
  }, [testConditionFn, tuples]);

  return factoryValue;
}

它的工作原理如下(Codesandbox:https://codesandbox.io/s/react-example-8o9ht):

import ReactDOM from "react-dom";
import React, { useMemo } from "react";
import { useFactory } from "react-js-utl/hooks";

const choice1 = {
  color: "red",
  label: "Fire"
};

const choice2 = {
  color: "green",
  label: "Grass"
};

const choice3 = {
  color: "blue",
  label: "Water"
};

function Example({ dep1, dep2, dep3 }) {
  const factoryValue = useFactory(
    () => [[dep1, choice1], [dep2, choice2], [() => dep3, choice3], "default"],

    // How to tell react-hooks/exhaustive-deps that it should warn me
    // that this array of deps is missing `dep1`, `dep2` and `dep3`?
    [] // No warning, but there should be one...
  );

  // Builtin `useMemo` hook works as expected.
  // react-hooks/exhaustive-deps warns me that the deps array is missing `dep1`, `dep2` and `dep3`:
  //
  //     React Hook useMemo has missing dependencies: 'dep1', 'dep2', and 'dep3'.
  //     Either include them or remove the dependency array. (react-hooks/exhaustive-deps)eslint
  //
  const dummyMemoizedValue = useMemo(() => (dep1 ? dep3 : dep2), []);

  return (
    <div>
      {JSON.stringify(factoryValue)} - {JSON.stringify(dummyMemoizedValue)}
    </div>
  );
}

ReactDOM.render(
  <Example dep1={false} dep2={true} dep3={false} />,
  document.getElementById("root")
);

factoryValue{ color: "green", label:"Grass" },因为dep2是唯一的真实道具,而choice2useFactory返回的对象。

但是useFactory自定义钩子缺少在其回调中使用的依赖项dep1dep2dep3,它们可能在重新渲染之间改变,因此该组件可能会呈现过时的数据。

如果有办法的话,我想react-hooks/exhaustive-deps提醒我。

谢谢!

0 个答案:

没有答案