https://github.com/nikaera/flutter_hooks_lint
A lint package for flutter_hooks in Flutter widgets!πͺπ΄ββ οΈ
https://github.com/nikaera/flutter_hooks_lint
analyzer dart flutter flutter-hooks linter
Last synced: 28 days ago
JSON representation
A lint package for flutter_hooks in Flutter widgets!πͺπ΄ββ οΈ
- Host: GitHub
- URL: https://github.com/nikaera/flutter_hooks_lint
- Owner: nikaera
- License: mit
- Created: 2024-02-20T14:36:42.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-10-21T14:16:36.000Z (8 months ago)
- Last Synced: 2024-10-21T22:55:22.675Z (8 months ago)
- Topics: analyzer, dart, flutter, flutter-hooks, linter
- Language: Dart
- Homepage: https://pub.dev/packages/flutter_hooks_lint
- Size: 45.9 KB
- Stars: 20
- Watchers: 2
- Forks: 1
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# flutter_hooks_lintπͺπ΄ββ οΈ
A lint package providing guidelines for using [flutter_hooks](https://pub.dev/packages/flutter_hooks) in your Flutter widget! π¦
* You can keep code that follows the rules outlined in the [official documentation of flutter_hooks](https://pub.dev/packages/flutter_hooks#rules). β
* A lint rules are available to **improve both performance and readability**. β¨
* A lint rules **supporting [`hooks_riverpod`](https://pub.dev/packages/hooks_riverpod) has been prepared**. π§βπ€βπ§The currently available lint rules are as follows:
| LintRule | Description | Quickfix |
| ------------- | ------------- | ------------- |
| [hooks_avoid_nesting](#hooks_avoid_nesting) | You should use Hooks only inside the build method of a Widget. | |
| [hooks_avoid_within_class](#hooks_avoid_within_class) | Hooks must not be defined within the class. | |
| [hooks_name_convention](#hooks_name_convention) | DO always prefix your hooks with use, https://pub.dev/packages/flutter_hooks#rules. | β |
| [hooks_extends](#hooks_extends) | Using Hooks inside a Widget other than HookWidget or HookConsumerWidget will result in an error at runtime. | β |
| [hooks_unuse_widget](#hooks_unuse_widget) | If you are not using Hooks inside of a Widget, you do not need HookWidget or HookConsumerWidget. | β |
| [hooks_memoized_consideration](#hooks_memoized_consideration) | Considering performance and functionality, there may be places where it is worth considering the use of useMemoized. | β |
| [hooks_callback_consideration](#hooks_callback_consideration) | There are cases where you can use useCallback, which is the syntax sugar for useMemoized. | β |
## Installation
Add both `flutter_hooks_lint` and `custom_lint` to your `pubspec.yaml`:
```yaml
dev_dependencies:
custom_lint:
flutter_hooks_lint:
```Enable custom_lint's plugin in your `analysis_options.yaml`:
```yaml
analyzer:
plugins:
- custom_lint
```## Enabling/disabling lints
By default when installing `flutter_hooks_lint`, most of the lints will be enabled.
You 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`
```yaml
analyzer:
plugins:
- custom_lintcustom_lint:
rules:
# Explicitly disable one lint rule
- hooks_unuse_widget: false
```## Running flutter_hooks_lint in the terminal/CI π€
Custom 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`.
Since your project should already have `custom_lint` installed, then you should be able to run:
```bash
# Install custom_lint for project
dart pub get custom_lint
# run custom_lint's command line in a project
dart run custom_lint
```Alternatively, you can globally install custom_lint:
```bash
# Install custom_lint for all projects
dart pub global activate custom_lint
# run custom_lint's command line in a project
custom_lint
```## All the lints
### hooks_avoid_nesting
**You should use Hooks only inside the build method of a Widget.**
* https://pub.dev/packages/flutter_hooks#rules
**Bad**:
```dart
@override
Widget build(BuildContext context) {
if (isEnable) {
final state = useState(0); // β
return Text(state.value.toString());
} else {
return SizedBox.shrink();
}
}
```**Good**:
```dart
@override
Widget build(BuildContext context) {
final state = useState(0); // β
return isEnable ?
Text(state.value.toString()) :
SizedBox.shrink();
}
```### hooks_avoid_within_class
Defining Custom Hooks within a class mixes the characteristics of class and method, leading to potentially complex code.
**Bad**
```dart
class TestHelper {
const TestHelper._();static void useEffectOnce(Dispose? Function() effect) { // β
useEffect(effect, const []);
}
}
```**Good**:
```dart
void useEffectOnce(Dispose? Function() effect) { // β
useEffect(effect, const []);
}
```### hooks_name_convention
**DO always prefix your hooks with use.**
* https://pub.dev/packages/flutter_hooks#rules.
**Bad**:
```dart
class WrongMethodWidget extends HookWidget {
@override
Widget build(BuildContext context) {
effectOnce(() { // β
return;
});
return Text('');
}
}
```**Good**:
```dart
class CorrectMethodWidget extends HookWidget {
@override
Widget build(BuildContext context) {
useEffectOnce(() { // β
return;
});
return Text('');
}
}
```### hooks_extends
**Using Hooks inside a Widget other than `HookWidget` or `HookConsumerWidget` will result in an error at runtime.**
**Bad**:
```dart
class RequiresHookWidget extends StatelessWidget { // β
@override
Widget build(BuildContext context) {
final state = useState(0);
return Text(state.value.toString());
}
}class RequiresConsumerHookWidget extends ConsumerWidget { // β
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = useState(0);
return Text(state.value.toString());
}
}
```**Good**:
```dart
class RequiresHookWidget extends HookWidget { // β
@override
Widget build(BuildContext context) {
final state = useState(0);
return Text(state.value.toString());
}
}class RequiresConsumerHookWidget extends HookConsumerWidget { // β
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = useState(0);
return Text(state.value.toString());
}
}
```### hooks_unuse_widget
If you are not using Hooks inside of a Widget, you do not need `HookWidget` or `HookConsumerWidget`.
**Bad**:
```dart
class UnuseHookWidget extends HookWidget { // β
@override
Widget build(BuildContext context) {
return SizedBox.shrink();
}
}class UnuseHookConsumerWidget extends HookConsumerWidget { // β
@override
Widget build(BuildContext context, WidgetRef ref) {
return SizedBox.shrink();
}
}
```**Good**:
```dart
class UnuseHookWidget extends StatelessWidget { // β
@override
Widget build(BuildContext context) {
return SizedBox.shrink();
}
}class UnuseHookConsumerWidget extends ConsumerWidget { // β
@override
Widget build(BuildContext context, WidgetRef ref) {
return SizedBox.shrink();
}
}
```### hooks_memoized_consideration
Considering functionality, there may be places where it is worth considering the use of `useMemoized`.
* https://api.flutter.dev/flutter/widgets/GlobalKey-class.html
**Bad**
```dart
class ConsiderationMemoizedWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final key = GlobalKey(); // β
final objectKey = GlobalObjectKey("object"); // β
return Column(
children: [key, objectKey]
.map((k) => Tooltip(
key: key,
message: 'Click me!',
))
.toList());
}
}
```**Good**
```dart
class ConsiderationMemoizedWidget extends HooksWidget {
@override
Widget build(BuildContext context) {
final key = useMemoized(() => GlobalKey()); // β
final objectKey = useMemoized(() => GlobalObjectKey("object")); // β
return Column(
children: [key, objectKey]
.map((k) => Tooltip(
key: key,
message: 'Click me!',
))
.toList());
}
}
```### hooks_callback_consideration
There are cases where you can use `useCallback`, which is the syntax sugar for `useMemoized`.
* https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useCallback.html
**Bad**
```dart
class ConsiderationMemoizedWidget extends HookWidget {
@override
Widget build(BuildContext context) {
final state = useMemoized(() => () => 0); // β
return Text(state.call().toString());
}
}
```**Good**
```dart
class ConsiderationMemoizedWidget extends HookWidget {
@override
Widget build(BuildContext context) {
final state = useCallback(() => 0); // β
return Text(state.call().toString());
}
}
```## Contribution π
Thanks for your interest! [Issues](https://github.com/nikaera/flutter_hooks_lint/issues/new) and PR are welcomed! π
I would be delighted if you could translate the documentation into natural English or add new lint rules!The project setup procedures for development are as follows:
1. Fork it ( https://github.com/nikaera/flutter_hooks_lint/fork )
2. Create your fix/feature branch (git checkout -b my-new-feature)
3. Install packages ( `flutter pub get` )
4. Run the test ( `dart run grinder` )
5. Add a test each time you modify
6. `4.` it is possible to check the operation by executing the command ( `dart run grinder` )
7. Commit your changes (git commit -am 'Add some feature')
8. Push to the branch (git push origin my-new-feature)
9. Create new Pull Request! π