mcpField
F
Flutter Conventions & Best Practices

Flutter Conventions & Best Practices

github.com/kaakati开发1064 次安装40 周前更新
代码仓库

关于 Flutter Conventions & Best Practices

面向 Flutter 开发者的参考 Skill,涵盖 Dart 3.x 语法、命名、项目结构、空安全、异步代码和 Widget 实践,并提供代码组织与编写示例。

主要功能

  1. 01Dart 3.x 模式匹配与记录
  2. 02文件和标识符命名规范
  3. 03分层式与功能式目录布局
  4. 04空安全指导
  5. 05async/await 错误处理
  6. 06Widget 构造实践

适用场景

  1. 01选择 Flutter 项目布局
  2. 02统一 Dart 命名方式
  3. 03审查异步代码
  4. 04改进 Widget 实现

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kaakati/rails-enterprise-dev --skill flutter-conventions-&-best-practices

安装后在 Claude Code 中输入/flutter-conventions-&-best-practices确认已加载。

详细介绍

Flutter 规范与最佳实践

Dart 3.x 特性

模式匹配
String describeUser(User user) {
  return switch (user) {
    User(role: 'admin', isActive: true) => 'Active administrator',
    User(role: 'user', isActive: true) => 'Active user',
    User(isActive: false) => 'Inactive account',
    _ => 'Unknown status',
  };
}
Records
(int, String) getUserInfo() => (123, 'John Doe');

final (id, name) = getUserInfo();
密封类
sealed class Result<T> {}
class Success<T> extends Result<T> {
  final T data;
  Success(this.data);
}
class Error<T> extends Result<T> {
  final String message;
  Error(this.message);
}

文件命名规范

  • 文件:snake_case.dart
  • 类:PascalCase
  • 变量/函数:camelCase
  • 常量:lowerCamelCase;编译时常量可使用 SCREAMING_SNAKE_CASE
// user_controller.dart
class UserController extends GetxController {
  static const int maxRetries = 3;
  static const String BASE_URL = 'https://api.example.com';
  
  final userName = 'John'.obs;
  
  void fetchUserData() {
    // ...
  }
}

目录组织

层级优先(推荐用于整洁架构):

lib/
├── domain/
├── data/
└── presentation/

功能优先(替代方案):

lib/
└── features/
    ├── auth/
    │   ├── domain/
    │   ├── data/
    │   └── presentation/
    └── profile/

空安全

// Use late for non-nullable fields initialized later
class MyController extends GetxController {
  late final UserRepository repository;
  
  @override
  void onInit() {
    super.onInit();
    repository = Get.find();
  }
}

// Use ? for nullable types
String? userName;

// Use ! only when absolutely certain
final name = userName!; // Use sparingly

// Prefer ?? for defaults
final displayName = userName ?? 'Guest';

Async/Await 最佳实践

// Use async/await for asynchronous operations
Future<User> fetchUser(String id) async {
  try {
    final response = await client.get(Uri.parse('/users/$id'));
    return User.fromJson(jsonDecode(response.body));
  } on SocketException {
    throw NetworkException();
  } catch (e) {
    throw UnknownException(e.toString());
  }
}

// Use Future.wait for parallel operations
Future<void> loadAllData() async {
  final results = await Future.wait([
    fetchUsers(),
    fetchSettings(),
    fetchPreferences(),
  ]);
}

// Use unawaited for fire-and-forget
unawaited(analytics.logEvent('page_view'));

文件内的代码组织

class MyClass {
  // 1. Constants
  static const int maxRetries = 3;
  
  // 2. Static fields
  static final instance = MyClass._();
  
  // 3. Instance fields
  final String id;
  final _isLoading = false.obs;
  
  // 4. Constructors
  MyClass(this.id);
  MyClass._();
  
  // 5. Getters/Setters
  bool get isLoading => _isLoading.value;
  
  // 6. Lifecycle methods
  @override
  void onInit() {}
  
  // 7. Public methods
  void publicMethod() {}
  
  // 8. Private methods
  void _privateMethod() {}
}

Widget 最佳实践

// Prefer const constructors
class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return const Text('Hello');
  }
}

// Extract widgets for reusability
class UserCard extends StatelessWidget {
  final User user;
  
  const UserCard({Key? key, required this.user}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Card(
      child: _buildContent(),
    );
  }
  
  Widget _buildContent() {
    return Column(
      children: [
        Text(user.name),
        Text(user.email),
      ],
    );
  }
}

评论

支持 Markdown