{"id":22003479,"url":"https://github.com/arthurgeron/eslint-plugin-react-usememo","last_synced_at":"2026-01-31T08:04:02.870Z","repository":{"id":48125159,"uuid":"516515359","full_name":"arthurgeron/eslint-plugin-react-usememo","owner":"arthurgeron","description":"Making components and hooks safe and scalable","archived":false,"fork":false,"pushed_at":"2025-04-11T14:06:00.000Z","size":777,"stargazers_count":76,"open_issues_count":4,"forks_count":7,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-31T22:47:12.776Z","etag":null,"topics":["eslint","eslint-plugin","hook","react","react-native"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"steadicat/eslint-plugin-react-memo","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arthurgeron.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-07-21T20:39:13.000Z","updated_at":"2025-07-07T06:37:52.000Z","dependencies_parsed_at":"2023-02-10T13:32:05.116Z","dependency_job_id":"85210028-e044-45ad-b752-42bd2f131696","html_url":"https://github.com/arthurgeron/eslint-plugin-react-usememo","commit_stats":{"total_commits":95,"total_committers":3,"mean_commits":"31.666666666666668","dds":0.5263157894736843,"last_synced_commit":"4a85d2296ed42b89099f5016ad753ae708a5aeef"},"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/arthurgeron/eslint-plugin-react-usememo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arthurgeron%2Feslint-plugin-react-usememo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arthurgeron%2Feslint-plugin-react-usememo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arthurgeron%2Feslint-plugin-react-usememo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arthurgeron%2Feslint-plugin-react-usememo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arthurgeron","download_url":"https://codeload.github.com/arthurgeron/eslint-plugin-react-usememo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arthurgeron%2Feslint-plugin-react-usememo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28934639,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T07:49:44.436Z","status":"ssl_error","status_checked_at":"2026-01-31T07:49:34.274Z","response_time":128,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eslint","eslint-plugin","hook","react","react-native"],"created_at":"2024-11-30T00:09:40.549Z","updated_at":"2026-01-31T08:04:02.865Z","avatar_url":"https://github.com/arthurgeron.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ESLint-Plugin-React-UseMemo\n\nThis plugin enforces the wrapping of complex objects or functions (which might generate unnecessary renders or side-effects) in `useMemo` or `useCallback`. It also allows you to programmatically enforce the wrapping of functional components in `memo`, and that all props and dependencies are wrapped in `useMemo`/`useCallback`.\n\n## Purpose\n\nThe objective is to ensure that your application's component tree and/or expensive lifecycles (such as React Native's FlatLists, useEffect, useMemo, etc.) only re-calculate or render again when absolutely necessary. By controlling expensive expressions, you can achieve optimal scalability and performance for your application.\n\n_**Note:**_ Use of memoization everywhere is not advised, as everything comes with a cost. Overusing memoization might slow down your application instead of speeding it up.\n\n## Guidelines for Memoization\n\n\u003e For more details, please refer to React's [documentation](https://react.dev/reference/react/useMemo) on hooks, re-rendering and memoization.\n\n### There are two primary rules for situations where dynamic objects should be memoed:\n\n1. Variables or expressions that return non-primitive objects or functions passed as props to other components.\n\n   **_Incorrect_**\n\n   ```js\n   function Component({ incomingData }) {\n     const complexData = {\n       ...incomingData,\n       checked: true,\n     }; // generated each render, breaks hooks shallow comparison\n\n     return \u003cSomeComponent data={complexData} /\u003e;\n   }\n   ```\n\n   **_Correct_**\n\n   ```js\n   function Component({ incomingData }) {\n     const complexData = useMemo(\n       () =\u003e ({\n         ...incomingData,\n         checked: true,\n       }),\n       [incomingData],\n     ); // generated only when incomingData changes\n\n     return \u003cSomeComponent data={complexData} /\u003e;\n   }\n   ```\n\n2. Variables or expressions that return non-primitive objects returned from custom hooks.\n\n   **_Incorrect_**\n\n   ```js\n   function useMyData({ incomingData }) {\n     const parsedData = parseData(incomingData); // generated each render\n\n     return parsedData; // Will result in loops passed as a dependency in other hooks(e.g. useMemo, useCallback, useEffect).\n   }\n   ```\n\n   **_Correct_**\n\n   ```js\n   function useMyData({ incomingData }) {\n     const parsedData = useMemo(() =\u003e parseData(incomingData), [incomingData]); // generated only when incomingData changes\n\n     return parsedData; // Won't generate loops if used as a dependency in hooks.\n   }\n   ```\n\n### It is not recommended to use memoization in the following cases:\n\n- When the resulting value (expression or variable) is primitive (string, number, boolean).\n\n  **_Incorrect_**\n\n  ```js\n  function Component() {\n    const width = useMemo(() =\u003e someValue * 10, []); // results in integer, wouldn't break hooks' shallow comparison; Memoizing this would only reduce performance\n\n    return \u003cSomeComponent width={width} /\u003e;\n  }\n  ```\n\n  **_Correct_**\n\n  ```js\n  function Component() {\n    const width = someValue * 10;\n\n    return \u003cSomeComponent width={width} /\u003e;\n  }\n  ```\n\n- If you're passing props to a native component of the framework (e.g. Div, Touchable, etc), except in some instances in react-native (e.g. FlatList).\n\n  **_Incorrect_**\n\n  ```js\n  function Component() {\n    const onClick = useCallback(() =\u003e {}, []);\n\n    return \u003cdiv onClick={onClick} /\u003e;\n  }\n  ```\n\n  **_Correct_**\n\n  ```js\n  function Component() {\n    const onClick = () =\u003e {};\n\n    return \u003cdiv onClick={onClick} /\u003e;\n  }\n  ```\n\n- Values that can be a global/context outside the react Context.\n  **_Incorrect_**\n\n  ```js\n  function Component() {\n    const breakpoints = [100];\n\n    return \u003cModal breakpoints={breakpoints}\u003e\n  }\n  ```\n\n  **_Correct_**\n\n  ```js\n  const breakpoints = [100];\n\n  function Component() {\n    return \u003cModal breakpoints={breakpoints}\u003e\n  }\n  ```\n\n## Installation\n\nInstall it with yarn:\n\n```\nyarn add @arthurgeron/eslint-plugin-react-usememo --dev\n```\n\nor npm:\n\n```\nnpm install @arthurgeron/eslint-plugin-react-usememo --save-dev\n```\n\n## Compatibility\n\nThis plugin targets ESLint v9+ (flat config). ESLint v8 is no longer supported. The package exposes named exports only.\n\n### ESLint v9 Configuration (eslint.config.js)\n\n#### Option 1: Use the plugin directly\n\n```js\nimport { flatConfig } from \"@arthurgeron/eslint-plugin-react-usememo\";\n\nexport default [\n  {\n    files: [\"**/*.js\", \"**/*.jsx\", \"**/*.ts\", \"**/*.tsx\"],\n    languageOptions: {\n      ecmaVersion: 2020,\n      sourceType: \"module\",\n      parserOptions: {\n        ecmaFeatures: {\n          jsx: true,\n        },\n      },\n    },\n    plugins: {\n      \"@arthurgeron/react-usememo\": flatConfig,\n    },\n    rules: {\n      \"@arthurgeron/react-usememo/require-usememo\": \"error\",\n      \"@arthurgeron/react-usememo/require-memo\": \"error\",\n      \"@arthurgeron/react-usememo/require-usememo-children\": \"error\",\n    },\n  },\n];\n```\n\n#### Option 2: Use the recommended config\n\n```js\nimport { flatConfig } from \"@arthurgeron/eslint-plugin-react-usememo\";\n\nexport default [\n  flatConfig.configs.recommended,\n];\n```\n\n#### Option 3: CommonJS syntax\n\n```js\nconst { flatConfig } = require(\"@arthurgeron/eslint-plugin-react-usememo\");\n\nmodule.exports = [\n  {\n    plugins: {\n      \"@arthurgeron/react-usememo\": flatConfig,\n    },\n    rules: {\n      \"@arthurgeron/react-usememo/require-usememo\": \"error\",\n      \"@arthurgeron/react-usememo/require-memo\": \"error\",\n      \"@arthurgeron/react-usememo/require-usememo-children\": \"error\",\n    },\n  },\n];\n```\n\nFor migration guidance, please refer to our [ESLint v9 Migration Guide](https://github.com/arthurgeron/eslint-plugin-react-usememo/blob/main/docs/rules/eslint-v9-migration-guide.md).\n\n## Examples\n\nFor a working example of ESLint v9 (flat config), please check the [examples directory](https://github.com/arthurgeron/eslint-plugin-react-usememo/tree/main/examples).\n\n## Rule #1: `require-usememo` **_(recommended)_**\n\nThis rule requires complex values (objects, arrays, functions, and JSX) that get passed props or referenced as a hook dependency to be wrapped in useMemo() or useCallback().\n\nOne of the great features of this rule is its amazing autofix functionality. It intelligently wraps necessary components with useMemo() or useCallback(), making your code more efficient and saving you valuable time.\n\nFor detailed examples, options available for this rule, and information about the autofix functionality, please refer to our [rules documentation](https://github.com/arthurgeron/eslint-plugin-react-usememo/blob/main/docs/rules/require-usememo.md).\n\n## Rule #2: `require-memo`\n\nThis rule requires all function components to be wrapped in `React.memo()`.\n\nFor detailed examples and usage of this rule, please refer to our [rules documentation](https://github.com/arthurgeron/eslint-plugin-react-usememo/blob/main/docs/rules/require-memo.md)\n\n## Rule #3: `require-usememo-children`\n\nThis rule requires complex values (objects, arrays, functions, and JSX) that get passed as children to be wrapped in `useMemo()` or `useCallback()`.\n\nFor detailed examples and options available for this rule, please refer to our [rules documentation](https://github.com/arthurgeron/eslint-plugin-react-usememo/blob/main/docs/rules/require-usememo-children.md).\n\n## Conclusion\n\nBy efficiently using `useMemo`, `useCallback`, and `React.memo()`, we can optimize our React and React Native applications. It allows us to control the re-calculation and re-rendering of components, offering better scalability and performance.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farthurgeron%2Feslint-plugin-react-usememo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farthurgeron%2Feslint-plugin-react-usememo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farthurgeron%2Feslint-plugin-react-usememo/lists"}