{"id":24108640,"url":"https://github.com/nikaera/flutter_hooks_lint","last_synced_at":"2025-05-12T20:13:16.527Z","repository":{"id":223503028,"uuid":"760500884","full_name":"nikaera/flutter_hooks_lint","owner":"nikaera","description":"A lint package for flutter_hooks in Flutter widgets!🪝🏴‍☠️","archived":false,"fork":false,"pushed_at":"2024-10-21T14:16:36.000Z","size":47,"stargazers_count":20,"open_issues_count":6,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-21T22:55:22.675Z","etag":null,"topics":["analyzer","dart","flutter","flutter-hooks","linter"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/flutter_hooks_lint","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nikaera.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2024-02-20T14:36:42.000Z","updated_at":"2024-10-21T14:07:55.000Z","dependencies_parsed_at":"2024-10-21T18:24:46.403Z","dependency_job_id":null,"html_url":"https://github.com/nikaera/flutter_hooks_lint","commit_stats":null,"previous_names":["nikaera/flutter_hooks_lint"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikaera%2Fflutter_hooks_lint","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikaera%2Fflutter_hooks_lint/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikaera%2Fflutter_hooks_lint/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikaera%2Fflutter_hooks_lint/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nikaera","download_url":"https://codeload.github.com/nikaera/flutter_hooks_lint/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233422972,"owners_count":18674089,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["analyzer","dart","flutter","flutter-hooks","linter"],"created_at":"2025-01-10T23:39:15.038Z","updated_at":"2025-05-12T20:13:16.504Z","avatar_url":"https://github.com/nikaera.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# flutter_hooks_lint🪝🏴‍☠️\n\n\u003cimg src=\"https://repository-images.githubusercontent.com/760500884/b32f5699-faa0-4abc-b31e-b1517c2f0cb1\" width=\"50%\"\u003e\n\n\u003ca href=\"https://pub.dartlang.org/packages/flutter_hooks_lint\"\u003e\n  \u003cimg src=\"https://img.shields.io/pub/v/flutter_hooks_lint.svg\" alt=\"flutter_hooks_lint package\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://pub.dev/packages/very_good_analysis\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/style-very__good__analysis-40c4ff.svg\" alt=\"very_good_analysis\" /\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/nikaera/flutter_hooks_lint/actions/workflows/project-ci.yaml\"\u003e\n  \u003cimg src=\"https://github.com/nikaera/flutter_hooks_lint/actions/workflows/project-ci.yaml/badge.svg\" alt=\"Build Status\"\u003e\n\u003c/a\u003e\n\nA lint package providing guidelines for using [flutter_hooks](https://pub.dev/packages/flutter_hooks) in your Flutter widget! 🦜\n\n* You can keep code that follows the rules outlined in the [official documentation of flutter_hooks](https://pub.dev/packages/flutter_hooks#rules). ⚓\n* A lint rules are available to **improve both performance and readability**. ✨\n* A lint rules **supporting [`hooks_riverpod`](https://pub.dev/packages/hooks_riverpod) has been prepared**. 🧑‍🤝‍🧑\n\nThe currently available lint rules are as follows:\n\n| LintRule  | Description | Quickfix |\n| ------------- | ------------- | ------------- |\n| [hooks_avoid_nesting](#hooks_avoid_nesting)  | You should use Hooks only inside the build method of a Widget. | |\n| [hooks_avoid_within_class](#hooks_avoid_within_class)  | Hooks must not be defined within the class. | |\n| [hooks_name_convention](#hooks_name_convention)  | DO always prefix your hooks with use, https://pub.dev/packages/flutter_hooks#rules. | ✅ |\n| [hooks_extends](#hooks_extends)  | Using Hooks inside a Widget other than HookWidget or HookConsumerWidget will result in an error at runtime. | ✅ |\n| [hooks_unuse_widget](#hooks_unuse_widget)  | If you are not using Hooks inside of a Widget, you do not need HookWidget or HookConsumerWidget. | ✅ |\n| [hooks_memoized_consideration](#hooks_memoized_consideration)  | Considering performance and functionality, there may be places where it is worth considering the use of useMemoized. | ✅ |\n| [hooks_callback_consideration](#hooks_callback_consideration)  | There are cases where you can use useCallback, which is the syntax sugar for useMemoized. | ✅ |\n\n![screencast](https://github.com/nikaera/flutter_hooks_lint/assets/1802476/bbea0791-502e-4091-8941-a94e15097752)\n\n## Installation\n\nAdd both `flutter_hooks_lint` and `custom_lint` to your `pubspec.yaml`:\n```yaml\ndev_dependencies:\n  custom_lint:\n  flutter_hooks_lint:\n```\n\nEnable custom_lint's plugin in your `analysis_options.yaml`:\n```yaml\nanalyzer:\n  plugins:\n    - custom_lint\n```\n\n## Enabling/disabling lints\n\nBy default when installing `flutter_hooks_lint`, most of the lints will be enabled.\n\nYou may dislike one of the various lint rules offered by `flutter_hooks_lint`. In that event, you can explicitly disable this lint rule for your project by modifying the `analysis_options.yaml`\n\n```yaml\nanalyzer:\n  plugins:\n    - custom_lint\n\ncustom_lint:\n  rules:\n    # Explicitly disable one lint rule\n    - hooks_unuse_widget: false\n```\n\n## Running flutter_hooks_lint in the terminal/CI 🤖\n\nCustom lint rules created by `flutter_hooks_lint` may not show-up in dart analyze. To fix this, you can run a custom command line: `custom_lint`.\n\nSince your project should already have `custom_lint` installed, then you should be able to run:\n\n```bash\n# Install custom_lint for project\ndart pub get custom_lint\n# run custom_lint's command line in a project\ndart run custom_lint\n```\n\nAlternatively, you can globally install custom_lint:\n\n```bash\n# Install custom_lint for all projects\ndart pub global activate custom_lint\n# run custom_lint's command line in a project\ncustom_lint\n```\n\n## All the lints\n\n### hooks_avoid_nesting\n\n**You should use Hooks only inside the build method of a Widget.**\n\n* https://pub.dev/packages/flutter_hooks#rules\n\n**Bad**:\n\n```dart\n@override\nWidget build(BuildContext context) {\n  if (isEnable) {\n    final state = useState(0); // ❌\n    return Text(state.value.toString());\n  } else {\n    return SizedBox.shrink();\n  }\n}\n```\n\n**Good**:\n\n```dart\n@override\nWidget build(BuildContext context) {\n    final state = useState(0); // ⭕\n    return isEnable ?\n      Text(state.value.toString()) :\n      SizedBox.shrink();\n}\n```\n\n### hooks_avoid_within_class\n\nDefining Custom Hooks within a class mixes the characteristics of class and method, leading to potentially complex code.\n\n**Bad**\n\n```dart\nclass TestHelper {\n  const TestHelper._();\n\n  static void useEffectOnce(Dispose? Function() effect) { // ❌\n    useEffect(effect, const []);\n  }\n}\n```\n\n**Good**:\n\n```dart\nvoid useEffectOnce(Dispose? Function() effect) { // ⭕\n  useEffect(effect, const []);\n}\n```\n\n### hooks_name_convention\n\n**DO always prefix your hooks with use.**\n\n* https://pub.dev/packages/flutter_hooks#rules.\n\n**Bad**:\n\n```dart\nclass WrongMethodWidget extends HookWidget {\n  @override\n  Widget build(BuildContext context) {\n    effectOnce(() { // ❌\n      return;\n    });\n    return Text('');\n  }\n}\n```\n\n**Good**:\n\n```dart\nclass CorrectMethodWidget extends HookWidget {\n  @override\n  Widget build(BuildContext context) {\n    useEffectOnce(() { // ⭕\n      return;\n    });\n    return Text('');\n  }\n}\n```\n\n### hooks_extends\n\n**Using Hooks inside a Widget other than `HookWidget` or `HookConsumerWidget` will result in an error at runtime.**\n\n**Bad**:\n\n```dart\nclass RequiresHookWidget extends StatelessWidget { // ❌\n  @override\n  Widget build(BuildContext context) {\n    final state = useState(0);\n    return Text(state.value.toString());\n  }\n}\n\nclass RequiresConsumerHookWidget extends ConsumerWidget { // ❌\n  @override\n  Widget build(BuildContext context, WidgetRef ref) {\n    final state = useState(0);\n    return Text(state.value.toString());\n  }\n}\n```\n\n**Good**:\n\n```dart\nclass RequiresHookWidget extends HookWidget { // ⭕\n  @override\n  Widget build(BuildContext context) {\n    final state = useState(0);\n    return Text(state.value.toString());\n  }\n}\n\nclass RequiresConsumerHookWidget extends HookConsumerWidget { // ⭕\n  @override\n  Widget build(BuildContext context, WidgetRef ref) {\n    final state = useState(0);\n    return Text(state.value.toString());\n  }\n}\n```\n\n### hooks_unuse_widget\n\nIf you are not using Hooks inside of a Widget, you do not need `HookWidget` or `HookConsumerWidget`.\n\n**Bad**:\n\n```dart\nclass UnuseHookWidget extends HookWidget { // ❌\n  @override\n  Widget build(BuildContext context) {\n    return SizedBox.shrink();\n  }\n}\n\nclass UnuseHookConsumerWidget extends HookConsumerWidget { // ❌\n  @override\n  Widget build(BuildContext context, WidgetRef ref) {\n    return SizedBox.shrink();\n  }\n}\n```\n\n**Good**:\n\n```dart\nclass UnuseHookWidget extends StatelessWidget { // ⭕\n  @override\n  Widget build(BuildContext context) {\n    return SizedBox.shrink();\n  }\n}\n\nclass UnuseHookConsumerWidget extends ConsumerWidget { // ⭕\n  @override\n  Widget build(BuildContext context, WidgetRef ref) {\n    return SizedBox.shrink();\n  }\n}\n```\n\n### hooks_memoized_consideration\n\nConsidering functionality, there may be places where it is worth considering the use of `useMemoized`.\n\n* https://api.flutter.dev/flutter/widgets/GlobalKey-class.html\n\n**Bad**\n\n```dart\nclass ConsiderationMemoizedWidget extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    final key = GlobalKey\u003cTooltipState\u003e(); // ❌\n    final objectKey = GlobalObjectKey\u003cTooltipState\u003e(\"object\"); // ❌\n    return Column(\n        children: [key, objectKey]\n            .map((k) =\u003e Tooltip(\n                  key: key,\n                  message: 'Click me!',\n                ))\n            .toList());\n  }\n}\n```\n\n**Good**\n\n```dart\nclass ConsiderationMemoizedWidget extends HooksWidget {\n  @override\n  Widget build(BuildContext context) {\n    final key = useMemoized(() =\u003e GlobalKey\u003cTooltipState\u003e()); // ⭕\n    final objectKey = useMemoized(() =\u003e GlobalObjectKey\u003cTooltipState\u003e(\"object\")); // ⭕\n    return Column(\n        children: [key, objectKey]\n            .map((k) =\u003e Tooltip(\n                  key: key,\n                  message: 'Click me!',\n                ))\n            .toList());\n  }\n}\n```\n\n### hooks_callback_consideration\n\nThere are cases where you can use `useCallback`, which is the syntax sugar for `useMemoized`.\n\n* https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useCallback.html\n\n**Bad**\n\n```dart\nclass ConsiderationMemoizedWidget extends HookWidget {\n  @override\n  Widget build(BuildContext context) {\n    final state = useMemoized(() =\u003e () =\u003e 0); // ❌\n    return Text(state.call().toString());\n  }\n}\n```\n\n**Good**\n\n```dart\nclass ConsiderationMemoizedWidget extends HookWidget {\n  @override\n  Widget build(BuildContext context) {\n    final state = useCallback(() =\u003e 0); // ⭕\n    return Text(state.call().toString());\n  }\n}\n```\n\n## Contribution 🎁\n\nThanks for your interest! [Issues](https://github.com/nikaera/flutter_hooks_lint/issues/new) and PR are welcomed! 🙌\nI would be delighted if you could translate the documentation into natural English or add new lint rules!\n\nThe project setup procedures for development are as follows:\n\n1. Fork it ( https://github.com/nikaera/flutter_hooks_lint/fork )\n2. Create your fix/feature branch (git checkout -b my-new-feature)\n3. Install packages  ( `flutter pub get` )\n4. Run the test ( `dart run grinder` )\n5. Add a test each time you modify\n6. `4.` it is possible to check the operation by executing the command ( `dart run grinder` )\n7. Commit your changes (git commit -am 'Add some feature')\n8. Push to the branch (git push origin my-new-feature)\n9. Create new Pull Request! 🎉\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikaera%2Fflutter_hooks_lint","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnikaera%2Fflutter_hooks_lint","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikaera%2Fflutter_hooks_lint/lists"}