skip to Main Content

I am upgrading my ESLint configuration from 8 to 9.14.0. But now after creating the eslint.config.js file, when I am running npx eslint, it is giving me weird errors. For example I have a component file named QuestionnaireTabNavigator.js, which is using some components and I am using them in my code but still getting issue in ESLint like:

   3:10  error  'Tab' is defined but never used                           no-unused-vars
   3:15  error  'Tabs' is defined but never used                          no-unused-vars
   9:8   error  'AssessmentSelector' is defined but never used            no-unused-vars
  10:8   error  'AssessmentsTable' is defined but never used              no-unused-vars
  11:8   error  'ErrorBoundaryWrapper' is defined but never used          no-unused-vars
  12:8   error  'Loader' is defined but never used                        no-unused-vars
  13:8   error  'QuestionnaireDetailedResults' is defined but never used  no-unused-vars
  14:8   error  'QuestionnaireSummary' is defined but never used  

What is the issue?

eslint.config.mjs:

import babelParser from "@babel/eslint-parser";
import pluginJs from "@eslint/js";
import importConfig from "eslint-plugin-import";
import pluginJest from "eslint-plugin-jest";
import jsdocConfig from "eslint-plugin-jsdoc";
import jsoncConfig from "eslint-plugin-jsonc";
import pluginPrettier from "eslint-plugin-prettier";
import pluginReact from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import sortKeysFixConfig from "eslint-plugin-sort-keys-fix";
import spellcheck from "eslint-plugin-spellcheck";
import testingPlugin from "eslint-plugin-testing-library";
import globals from "globals";

const config = [
    pluginJs.configs.recommended,
    {
        "files": ["**/*.{js,mjs,cjs,jsx}"],
        "languageOptions": {
            "ecmaVersion": 2020,
            "globals": {
                ...globals.es2021,
                ...globals.node,
                ...globals.browser,
                "describe": "readonly",
                "expect": "readonly",
                "indexedDB": "readonly",
                "it": "readonly",
                "jest": "readonly",
                "test": "readonly"
            },
            "parser": babelParser,
            "parserOptions": {
                "babelOptions": {
                    "babelrc": false,
                    "configFile": false,
                    "presets": [["@babel/preset-react", { "runtime": "automatic" }], "@babel/preset-env"]
                },
                "ecmaFeatures": {
                    "jsx": true
                },
                "requireConfigFile": false,
                "sourceType": "module"
            }
        },
        "plugins": {
            "import": importConfig,
            "jsdoc": jsdocConfig,
            "jsonc": jsoncConfig,
            "prettier": pluginPrettier,
            "react": pluginReact,
            "react-hooks": reactHooks,
            "sort-keys-fix": sortKeysFixConfig,
            "spellcheck": spellcheck,
            "testing-library": testingPlugin
        },
        "rules": {
            "array-bracket-newline": ["error", "consistent"],
            "array-bracket-spacing": ["error", "never"],
            "array-callback-return": "error",
            "array-element-newline": [
                "error",
                {
                    "ArrayExpression": "consistent",
                    "ArrayPattern": { "minItems": 3 }
                }
            ],
            "arrow-spacing": "error",
            "brace-style": ["error", "1tbs"],
            "camelcase": ["error", { "ignoreDestructuring": true, "properties": "never" }],
            "comma-dangle": ["error", "never"],
            "comma-spacing": [
                "error",
                {
                    "after": true,
                    "before": false
                }
            ],
            "curly": ["error", "all"],
            "default-case": "off",
            "eqeqeq": ["error", "always"],
            "func-call-spacing": ["error", "never"],
            "function-call-argument-newline": ["error", "consistent"],
            "import/first": "off",
            "import/order": ["error", { "groups": ["builtin", "external", "internal", "parent", "sibling", "index"] }],
            "indent": ["error", 4, { "SwitchCase": 1, "ignoredNodes": ["ConditionalExpression"] }],
            "jest/no-mocks-import": "off",
            "jsdoc/newline-after-description": 0,
            // Required for vs code auto formatting
            "jsdoc/require-hyphen-before-param-description": 1,

            "jsdoc/require-jsdoc": [
                "error",
                {
                    "require": {
                        "ArrowFunctionExpression": true,
                        "ClassExpression": true,
                        "FunctionDeclaration": true,
                        "FunctionExpression": true,
                        "MethodDefinition": true
                    }
                }
            ],
            "jsonc/sort-keys": "error",
            "keyword-spacing": ["error", { "after": true, "before": true }],
            "max-len": [
                "error",
                {
                    "code": 120,
                    "ignorePattern": "".*": ".*"" // Ignore pattern for strings in json as they can't be broken in multi lines
                }
            ],
            "no-console": "error",
            "no-dupe-else-if": "error",
            "no-extend-native": "off",
            "no-nested-ternary": "error",
            // "no-unused-vars": "warn",
            "no-useless-escape": "off",
            "no-var": "error",
            "object-curly-newline": ["error", { "consistent": true, "multiline": true }],
            "object-curly-spacing": ["error", "always"],
            "object-property-newline": ["error", { "allowAllPropertiesOnSameLine": true }],
            "padding-line-between-statements": [
                "error",
                // Always one empty line before return statement
                {
                    "blankLine": "always",
                    "next": "return",
                    "prev": "*"
                },
                // Always one empty line between methods
                {
                    "blankLine": "always",
                    "next": ["block-like", "multiline-block-like"],
                    "prev": ["block-like", "multiline-block-like"]
                },
                // Avoids more than one empty line
                {
                    "blankLine": "never",
                    "next": "empty",
                    "prev": "empty"
                }
            ],
            "prefer-const": "error",
            "quote-props": ["error", "always"],
            "quotes": ["error", "double"],
            "radix": "off",
            "react-hooks/exhaustive-deps": "error",
            "react-hooks/rules-of-hooks": "error",
            "react/jsx-boolean-value": ["warn", "always"],
            "react/jsx-closing-bracket-location": "error",
            "react/jsx-closing-tag-location": "error",
            "react/jsx-curly-brace-presence": [
                "error",
                {
                    "children": "ignore",
                    "props": "always"
                }
            ],
            "react/jsx-tag-spacing": ["error", { "beforeSelfClosing": "always" }],
            "react/no-multi-comp": ["error", { "ignoreStateless": true }],
            "react/react-in-jsx-scope": "off",
            "semi": ["error", "always"],
            "sort-keys": [
                "error",
                "asc",
                {
                    "caseSensitive": true,
                    "minKeys": 2,
                    "natural": false
                }
            ],
            "sort-keys-fix/sort-keys-fix": "error",
            "space-before-blocks": "error",
            "space-infix-ops": ["error", { "int32Hint": false }],
            "testing-library/no-node-access": "off"
        },
        "settings": {
            "react": {
                // Only needed for older React versions
                "fragment": "Fragment",
                // Automatically detect React version
                "pragma": "React",
                // Only needed for older React versions
                "runtime": "automatic",
                "version": "detect" // Use React 17+ JSX transform
            }
        }
    },
    {
        "files": ["**/*.test.{js,mjs,cjs,jsx}"],
        "languageOptions": {
            "globals": {
                ...globals.jest,
                ...globals.browser,
                ...globals.node,
                "describe": "readonly",
                "expect": "readonly",
                "indexedDB": "readonly",
                "it": "readonly",
                "jest": "readonly",
                "test": "readonly"
            }
        },
        "plugins": {
            "jest": pluginJest
        },
        "rules": {
            "react/react-in-jsx-scope": "off"
        },
        "settings": {
            "react": {
                "version": "detect"
            }
        }
    }
];

export default config;

package.json file:

{
    "browserslist": [
        ">0.2%",
        "not dead",
        "not op_mini all"
    ],
    "dependencies": {
        "@types/jest": "^29.5.11",
        "ajv": "^8.17.1",
        "awesome-debounce-promise": "~2.1.0",
        "axios": "~1.7.2",
        "bootstrap": "~5.3.2",
        "dotenv": "^16.4.1",
        "i18next": "~23.15.1",
        "i18next-http-backend": "~2.6.1",
        "jest-mock-axios": "~4.7.3",
        "lodash": "~4.17.21",
        "moment": "~2.30.1",
        "moment-timezone": "^0.5.43",
        "react": "~18.3.1",
        "react-bootstrap": "~2.10.2",
        "react-bootstrap-icons": "~1.11.4",
        "react-component-export-image": "~1.0.6",
        "react-dom": "~18.3.1",
        "react-draggable": "^4.4.6",
        "react-dropzone": "^14.2.3",
        "react-error-boundary": "^4.0.13",
        "react-i18next": "~15.0.1",
        "react-icons": "~5.3.0",
        "react-infinite-scroller": "~1.2.6",
        "react-intersection-observer": "~9.13.0",
        "react-leaflet": "~4.2.1",
        "react-multi-select-component": "~4.3.4",
        "react-router": "~6.26.2",
        "react-router-dom": "~6.26.2",
        "react-router-prompt": "^0.7.0",
        "react-scroll": "~1.9.0",
        "react-select": "~5.8.0",
        "react-switch": "~7.0.0",
        "react-tabs": "~6.0.2",
        "react-toastify": "~10.0.4",
        "socket.io-client": "~4.8.0",
        "use-csv-downloader": "0.0.0",
        "web-vitals": "~4.2.2"
    },
    "devDependencies": {
        "@babel/eslint-parser": "~7.25.9",
        "@eslint/js": "^9.14.0",
        "@testing-library/dom": "~10.4.0",
        "@testing-library/jest-dom": "~6.6.3",
        "@testing-library/react": "~16.0.1",
        "@testing-library/user-event": "~14.5.1",
        "@typescript-eslint/eslint-plugin": "~8.13.0",
        "@typescript-eslint/parser": "~8.13.0",
        "eslint": "~9.14.0",
        "eslint-config-prettier": "~9.1.0",
        "eslint-config-react-app": "~7.0.1",
        "eslint-plugin-import": "~2.31.0",
        "eslint-plugin-jest": "~28.9.0",
        "eslint-plugin-jsdoc": "^50.5.0",
        "eslint-plugin-jsonc": "~2.18.1",
        "eslint-plugin-jsx-a11y": "~6.10.2",
        "eslint-plugin-prettier": "~5.2.1",
        "eslint-plugin-react": "^7.37.2",
        "eslint-plugin-react-hooks": "~5.0.0",
        "eslint-plugin-sort-keys-fix": "~1.1.2",
        "eslint-plugin-spellcheck": "0.0.20",
        "eslint-plugin-testing-library": "~6.4.0",
        "fake-indexeddb": "6.0.0",
        "globals": "^15.12.0",
        "pre-commit": "~1.2.2",
        "prettier": "~3.3.3",
        "prettier-eslint": "~16.3.0",
        "prettier-eslint-cli": "~8.0.1",
        "react-scripts": "~5.0.1",
        "sass": "~1.80.6",
        "stylelint": "~16.10.0",
        "stylelint-config-prettier": "~9.0.5",
        "stylelint-config-standard-scss": "~13.1.0",
        "stylelint-prettier": "~5.0.2",
        "stylelint-scss": "~6.8.1"
    },
    "eslintConfig": {
        "extends": [
            "react-app",
            "react-app/jest"
        ]
    },
    "jest": {
        "collectCoverageFrom": [
            "src/**/*.js",
            "!src/**/*.scss",
            "!src/assets/**/*.js"
        ],
        "coverageThreshold": {
            "global": {
                "branches": 50,
                "functions": 50,
                "lines": 65,
                "statements": 65
            }
        }
    },
    "name": "imp-fe",
    "pre-commit": [
        "lint-pre-commit",
        "test-pre-commit"
    ],
    "private": true,
    "scripts": {
        "build": "react-scripts build",
        "eject": "react-scripts eject",
        "format": "npm run prettier-fix && npm run lint-fix",
        "lint": "npm run lint-check && npm run stylelint",
        "lint-check": "eslint src/ --ignore-pattern 'src/__mocks__/'",
        "lint-fix": "npm run lint-check -- --fix",
        "lint-pre-commit": "FILE_DIFF=$(git diff --name-only --cached --diff-filter=ACMR | grep .js$ | sed 's#/[^/]*$##') && [ '$FILE_DIFF' != '' ] && (eslint --ext .jsx --ext .js --ext .json $(echo $FILE_DIFF) && npm run stylelint) || exit 0",
        "prettier-fix": "npx prettier --write src/",
        "pull-latest-and-verify": "npm run pull-latest-code && node ./.dev/check_if_env_latest.js",
        "pull-latest-code": "git pull && npm i",
        "start": "react-scripts start",
        "stylelint": "npx stylelint 'src/**/*.{css,scss}'",
        "stylelint-fix": "npm run stylelint -- --fix",
        "test": "react-scripts test --maxWorkers 1",
        "test-coverage": "npm run test -- --coverage --watchAll=false",
        "test-no-watch": "npm run test -- --watchAll=false",
        "test-pre-commit": "FILE_DIFF=$(git diff --name-only --cached --diff-filter=ACMR | grep .js$ | sed 's#/[^/]*$##') && [ '$FILE_DIFF' != '' ] && (npm run test-no-watch -- $(echo $FILE_DIFF) --passWithNoTests) || exit 0"
    },
    "version": "24.8.0"
}

Component file QuestionnaireTabNavigator.js:

import PropTypes from "prop-types";
import { useCallback, useContext, useState } from "react";
import { Tab, Tabs } from "react-bootstrap";
import { withTranslation } from "react-i18next";
import { useNavigate, useSearchParams } from "react-router-dom";
import { CATEGORY_WISE_DATA_STRUCTURE, CATEGORY_WISE_DETAILED_RESULT } from "../../App.Constants";
import { QuestionnaireContext } from "../../contexts/QuestionnaireContext";
import { UserContext } from "../../contexts/UserContext";
import AssessmentSelector from "../AssessmentSelector/AssessmentSelector";
import AssessmentsTable from "../AssessmentsTable/AssessmentsTable";
import ErrorBoundaryWrapper from "../ErrorBoundaryWrapper/ErrorBoundaryWrapper";
import Loader from "../Loaders/Loader/Loader";
import QuestionnaireDetailedResults from "../QuestionnaireDetailedResults/QuestionnaireDetailedResults";
import QuestionnaireSummary from "../QuestionnaireSummary/QuestionnaireSummary";
import "./QuestionnaireTabNavigator.scss";

/**
 *
 * @param {*} props - Parent props
 * @returns {Element} - Returns multiple tabs with different sub components
 */
const QuestionnaireTabNavigator = ({ t }) => {
    const navigate = useNavigate();
    const { fetchAssessmentsList, "allAssessmentsData": apiResponse } = useContext(QuestionnaireContext);

    const { user } = useContext(UserContext);
    const [searchParams] = useSearchParams();
    const section = searchParams.get("section");

    /**
     * Added this extra check for apiResponse for smooth transitioning.
     * Loader will be visible based on current state value.
     * Also updating these state values from AssessmentSelector component.
     */
    const [benchmarkingData, setBenchmarkingData] = useState(!apiResponse.length ? CATEGORY_WISE_DATA_STRUCTURE : null);
    const [detailedResults, setDetailedResults] = useState(!apiResponse.length ? CATEGORY_WISE_DETAILED_RESULT : null);

    let tab = "assessments";
    if (window.location.pathname.includes("summary")) {
        tab = "summary";
    } else if (window.location.pathname.includes("detailed-results")) {
        tab = "detailed-results";
    }
    const [selectedTab, setSelectedTab] = useState(tab);

    const handleTabSelect = useCallback(
        (tab) => {
            if (tab === "detailed-results") {
                navigate(
                    `/${user.selectedTenant}/maturity-assessment/detailed-results${
                        section ? `section=${section}` : ""
                    }`,
                    {
                        "state": { "redirect": "no" }
                    }
                );
            } else if (tab === "summary") {
                navigate(`/${user.selectedTenant}/maturity-assessment/summary`, {
                    "state": { "redirect": "no" }
                });
            } else {
                navigate(`/${user.selectedTenant}/maturity-assessment/all-assessments`, {
                    "state": { "redirect": "no" }
                });
            }
        },
        [navigate, section, user.selectedTenant]
    );

    const setStateMethod = selectedTab === "detailed-results" ? setDetailedResults : setBenchmarkingData;

    return (
        <div
            className={"QuestionnaireTabNavigator bottom-border-tab-variant"}
            data-testid={"QuestionnaireTabNavigator"}
        >
            {selectedTab !== "assessments" ? (
                <AssessmentSelector
                    assessmentsList={apiResponse}
                    selectedTab={selectedTab}
                    setStateMethod={setStateMethod}
                />
            ) : null}

            <Tabs
                activeKey={selectedTab}
                id={"questionnaire-tab-navigator"}
                transition={false}
                onSelect={handleTabSelect}
            >
                <Tab eventKey={"assessments"} title={t("questionnaire.tab_navigator.assessments")}>
                    <ErrorBoundaryWrapper componentTitle={"Assessment table"}>
                        <AssessmentsTable apiResponse={apiResponse} fetchAssessmentsList={fetchAssessmentsList} />
                    </ErrorBoundaryWrapper>
                </Tab>
                <Tab eventKey={"summary"} title={t("questionnaire.tab_navigator.summary")}>
                    <ErrorBoundaryWrapper componentTitle={"Questionnaire Summary"}>
                        {benchmarkingData ? (
                            <QuestionnaireSummary benchmarkingData={benchmarkingData} setSelectedTab={setSelectedTab} />
                        ) : (
                            <Loader />
                        )}
                    </ErrorBoundaryWrapper>
                </Tab>
                <Tab eventKey={"detailed-results"} title={t("questionnaire.tab_navigator.detailed-results")}>
                    <ErrorBoundaryWrapper componentTitle={"Questionnaire Detailed Results"}>
                        {detailedResults ? (
                            <QuestionnaireDetailedResults detailedResults={detailedResults} />
                        ) : (
                            <Loader />
                        )}
                    </ErrorBoundaryWrapper>
                </Tab>
            </Tabs>
        </div>
    );
};

QuestionnaireTabNavigator.propTypes = {
    "t": PropTypes.func
};

export default withTranslation()(QuestionnaireTabNavigator);

2

Answers


  1. This issue arises because ESLint is enforcing the no-unused-vars rule, which flags any variables, imports, or components that are defined but not used in your code. This is often helpful to prevent unnecessary or redundant code, but it can be annoying when you are in the process of refactoring or temporarily not using a variable.

    Here are several ways to resolve or suppress these errors:

    Change ESLint Rule Configuration

    If you prefer to keep the unused variables (perhaps for future use or refactoring purposes), you can modify the ESLint configuration to either:

    • Warn instead of error:

      This will prevent the ESLint errors but still notify you about unused variables:

      In your .eslintrc.js or eslint.config.mjs, change the no-unused-vars rule to "warn":

      "no-unused-vars": "warn"
      
    • Turn off the rule entirely:

      If you don’t want ESLint to check for unused variables at all, you can disable the rule entirely:

      "no-unused-vars": "off"
      

    Conclusion

    • Best Practice: Remove unused variables or imports to keep your code clean and maintainable.
    • Alternatives: If you prefer to keep the variables, you can adjust the ESLint rule settings to "warn" or "off" depending on your preference.
    • Inline ESLint Disabling: For specific cases, you can disable the rule for a line or block of code using inline comments.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search