MST

星途 面试题库

面试题:Flutter 中 StatefulWidget 与 Provider 在复杂业务场景的架构设计

假设要开发一个电商应用,其中涉及商品列表展示、购物车管理、用户登录等复杂业务场景。请描述如何基于 StatefulWidget 和 Provider 设计一个清晰、可维护且高效的架构,包括不同业务模块的状态管理如何划分,以及它们之间如何通过 Provider 进行通信和数据共享。
30.9万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试

1. 架构设计概述

基于 StatefulWidgetProvider 构建电商应用架构,旨在将不同业务模块的状态管理进行合理划分,利用 Provider 实现高效的数据共享与通信,以确保代码的清晰性和可维护性。

2. 业务模块状态管理划分

  • 商品列表展示
    • 状态:商品列表数据(如商品信息、价格、库存等)、当前筛选条件、加载状态(是否正在加载更多商品)。
    • 管理方式:创建一个 ChangeNotifier 类,例如 ProductListProvider,用于管理这些状态。将商品数据获取逻辑封装在该类中,可通过网络请求获取商品列表数据并更新状态。
    • 示例代码
class ProductListProvider extends ChangeNotifier {
  List<Product> _products = [];
  bool _isLoading = false;
  String _filter = '';

  List<Product> get products => _products;
  bool get isLoading => _isLoading;
  String get filter => _filter;

  Future<void> fetchProducts() async {
    _isLoading = true;
    notifyListeners();
    try {
      // 模拟网络请求获取商品数据
      List<Product> newProducts = await ProductService.fetchProducts();
      _products = newProducts;
    } catch (e) {
      // 处理错误
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  void updateFilter(String newFilter) {
    _filter = newFilter;
    notifyListeners();
  }
}
  • 购物车管理
    • 状态:购物车中的商品列表、商品数量变化、总价计算。
    • 管理方式:创建 CartProvider 类继承自 ChangeNotifier。在该类中维护购物车商品列表,提供添加、删除、更新商品数量等方法,并在状态变化时通知监听器。
    • 示例代码
class CartProvider extends ChangeNotifier {
  List<CartItem> _cartItems = [];

  List<CartItem> get cartItems => _cartItems;
  double get totalPrice {
    double total = 0;
    for (var item in _cartItems) {
      total += item.product.price * item.quantity;
    }
    return total;
  }

  void addToCart(Product product) {
    for (var item in _cartItems) {
      if (item.product.id == product.id) {
        item.quantity++;
        notifyListeners();
        return;
      }
    }
    _cartItems.add(CartItem(product, 1));
    notifyListeners();
  }

  void removeFromCart(CartItem item) {
    _cartItems.remove(item);
    notifyListeners();
  }

  void updateQuantity(CartItem item, int newQuantity) {
    item.quantity = newQuantity;
    notifyListeners();
  }
}
  • 用户登录
    • 状态:用户登录状态(已登录/未登录)、用户信息(用户名、邮箱等)。
    • 管理方式:创建 UserProvider 类继承自 ChangeNotifier。通过方法实现登录、登出逻辑,并更新登录状态和用户信息。
    • 示例代码
class UserProvider extends ChangeNotifier {
  bool _isLoggedIn = false;
  User? _user;

  bool get isLoggedIn => _isLoggedIn;
  User? get user => _user;

  Future<void> login(String username, String password) async {
    try {
      // 模拟登录验证
      User loggedInUser = await UserService.login(username, password);
      _isLoggedIn = true;
      _user = loggedInUser;
    } catch (e) {
      // 处理登录错误
    } finally {
      notifyListeners();
    }
  }

  void logout() {
    _isLoggedIn = false;
    _user = null;
    notifyListeners();
  }
}

3. 通过 Provider 进行通信和数据共享

  • 顶层包裹:在应用的顶层(例如 main.dart 中的 MaterialAppCupertinoApp 之上),使用 MultiProvider 来包裹整个应用,将各个业务模块的 Provider 都注册进来。
void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => ProductListProvider()),
        ChangeNotifierProvider(create: (_) => CartProvider()),
        ChangeNotifierProvider(create: (_) => UserProvider()),
      ],
      child: MyApp(),
    ),
  );
}
  • 数据获取与共享:在各个 StatefulWidget 中,通过 Provider.of 获取所需的状态管理对象。例如,在商品列表页面获取 ProductListProvider 以展示商品数据。
class ProductListPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final productListProvider = Provider.of<ProductListProvider>(context);
    return Scaffold(
      appBar: AppBar(title: Text('商品列表')),
      body: productListProvider.isLoading
         ? Center(child: CircularProgressIndicator())
          : ListView.builder(
              itemCount: productListProvider.products.length,
              itemBuilder: (context, index) {
                Product product = productListProvider.products[index];
                return ListTile(
                  title: Text(product.name),
                  subtitle: Text('价格: ${product.price}'),
                );
              },
            ),
    );
  }
}
  • 模块间通信:不同业务模块间可通过共享的状态管理对象进行通信。例如,当用户登录后,购物车模块可根据 UserProvider 中的登录状态来决定是否显示保存的购物车数据。
class CartPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final userProvider = Provider.of<UserProvider>(context);
    final cartProvider = Provider.of<CartProvider>(context);
    return Scaffold(
      appBar: AppBar(title: Text('购物车')),
      body: userProvider.isLoggedIn
         ? ListView.builder(
              itemCount: cartProvider.cartItems.length,
              itemBuilder: (context, index) {
                CartItem item = cartProvider.cartItems[index];
                return ListTile(
                  title: Text(item.product.name),
                  subtitle: Text('数量: ${item.quantity} 总价: ${item.product.price * item.quantity}'),
                );
              },
            )
          : Center(child: Text('请先登录')),
    );
  }
}

通过以上架构设计,不同业务模块的状态管理得到清晰划分,并且通过 Provider 实现了高效的通信和数据共享,使整个电商应用的代码结构清晰、易于维护。