hook-use-state

Try in Playground
react-best-practicesBest PracticeWarning

0

No tags

No CWE or CVE

This rule checks whether:

  • the result is destructured
  • the user has destructured the setter
  • the setter has followed the proper naming convention

View a similar ESLint rule.

Ast Rule: assignment


hook-use-state

How to write a rule
/**
 * is the function name useState
 */
function checkIfUseState(value) {
  if (value === "useState") {
    return true;
  } else {
    return false;
  }
}

/**
 * used to check if the right side of an assignment is either:
 * React.useState
 * useState
 */
function checkIfReactUseStateHook(right) {
  if (!right.functionName) return false;
  if (right.functionName.parent?.value === "React") {
    if (checkIfUseState(right.functionName.name?.value)) {
      return true;
    }
  }
  if (checkIfUseState(right.functionName.value)) {
    return true;
  }
  return false;
}

/**
 *
 */
function checkIfValidSetter(value) {
  if (!value || value.length < 5) return false;
  const isPascalCase = value[3].toUpperCase() === value[3];
  if (value.startsWith("set") && isPascalCase) {
    return true;
  } else {
    return false;
  }
}

/**
 * handles all the logic when Codiga hits an assignment in file's AST
 */
function visit(node, filename, code) {
  if (!node || !node.left || !node.right) return;

  const isReactUseStateHook = checkIfReactUseStateHook(node.right);
  if (!isReactUseStateHook) return;

  /**
   * the left side of the assignment isn't destructured
   */
  if (!node.left.elements) {
    const notDestructuredError = buildError(
      node.left.start.line,
      node.left.start.col,
      node.left.end.line,
      node.left.end.col,
      "useState call is not destructured into value + setter pair",
      "WARNING",
      "BEST_PRACTICES"
    );

    const notDestructuredEdit = [
      buildEditUpdate(
        node.left.start.line,
        node.left.start.col,
        node.left.end.line,
        node.left.end.col,
        `[state, setState]`
      ),
    ];

    const notDestructuredFix = buildFix(`destructure`, notDestructuredEdit);

    addError(notDestructuredError.addFix(notDestructuredFix));
    return;
  }

  /**
   * less than the standard 2 (getter + setter) values were destructured
   */
  if (node.left.elements.length < 2) {
    const badDestructing = buildError(
      node.left.start.line,
      node.left.start.col,
      node.left.end.line,
      node.left.end.col,
      `Destructure both value + setter from useState`,
      "WARNING",
      "BEST_PRACTICES"
    );

    addError(badDestructing);
    return;
  }

  /**
   * the setter naming doesn't follow convention
   */
  const setterNode = node.left.elements[1];
  if (!setterNode?.value) return;
  const isValidSetter = checkIfValidSetter(setterNode.value);
  if (isValidSetter) return;

  const setterNamingError = buildError(
    setterNode.start.line,
    setterNode.start.col,
    setterNode.end.line,
    setterNode.end.col,
    `Your setter does not follow the standard (setThing) naming convention`,
    "WARNING",
    "BEST_PRACTICES"
  );

  addError(setterNamingError);
}

valid-use-state.jsx

Expected test result: no error

const [state, setState] = useState("");
const [state, setState] = React.useState("");

invalid-setter-naming.jsx

Expected test result: has error

const [state, setter] = useState("");
const [state, updateState] = useState("");
const [state, deleteState] = useState("");
const [state, removeState] = useState("");

missing-setter.jsx

Expected test result: has error

const [state] = useState("");
const [state] = useState("");
Add comment

Log in to add a comment


    Be the first one to leave a comment!

Codiga Logo
Codiga Hub
  • Rulesets
  • Playground
  • Snippets
  • Cookbooks
Legal
  • Security
  • Privacy Policy
  • Code Privacy
  • Terms of Service
soc-2 icon

We are SOC-2 Compliance Certified

G2 high performer medal

Codiga – All rights reserved 2022.