You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将基于Provider的Flutter项目迁移至flutter_riverpod?

Provider转flutter_riverpod 转换方案

一、原Provider核心代码示例(模拟常见业务实现)

1. RosterDataProvider(ChangeNotifier)

import 'package:flutter/material.dart';

class RosterDataProvider extends ChangeNotifier {
  List<String> _rosterList = ['张三', '李四', '王五'];
  List<String> _leaveList = [];

  List<String> get rosterList => _rosterList;
  List<String> get leaveList => _leaveList;

  void addLeave(String name) {
    if (_rosterList.contains(name)) {
      _rosterList.remove(name);
      _leaveList.add(name);
      notifyListeners();
    }
  }

  void cancelLeave(String name) {
    if (_leaveList.contains(name)) {
      _leaveList.remove(name);
      _rosterList.add(name);
      notifyListeners();
    }
  }
}

2. MainScreen(Provider消费)

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'leave_page.dart';

class MainScreen extends StatelessWidget {
  const MainScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('排班列表')),
      body: Consumer<RosterDataProvider>(
        builder: (context, provider, child) {
          return ListView.builder(
            itemCount: provider.rosterList.length,
            itemBuilder: (context, index) {
              final name = provider.rosterList[index];
              return ListTile(
                title: Text(name),
                trailing: ElevatedButton(
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => LeavePage(name: name),
                      ),
                    );
                  },
                  child: const Text('申请请假'),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

3. LeavePage(Provider操作)

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'roster_data_provider.dart';

class LeavePage extends StatelessWidget {
  final String name;
  const LeavePage({super.key, required this.name});

  @override
  Widget build(BuildContext context) {
    final provider = Provider.of<RosterDataProvider>(context, listen: false);
    return Scaffold(
      appBar: AppBar(title: const Text('申请请假')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('确认${name}请假吗?'),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                provider.addLeave(name);
                Navigator.pop(context);
              },
              child: const Text('确认请假'),
            ),
            const SizedBox(height: 10),
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('取消'),
            ),
          ],
        ),
      ),
    );
  }
}

4. 全局注册Provider

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => RosterDataProvider(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: const MainScreen(),
    );
  }
}

二、flutter_riverpod 转换实现

1. 依赖准备

确保pubspec.yaml添加依赖:

dependencies:
  flutter_riverpod: ^2.3.0
  flutter:
    sdk: flutter

2. RosterState 状态类与 RosterNotifier

import 'package:flutter_riverpod/flutter_riverpod.dart';

// 不可变状态类,存储核心数据
class RosterState {
  final List<String> rosterList;
  final List<String> leaveList;

  RosterState({
    required this.rosterList,
    required this.leaveList,
  });

  // 生成新状态的复制方法,保证状态不可变
  RosterState copyWith({
    List<String>? rosterList,
    List<String>? leaveList,
  }) {
    return RosterState(
      rosterList: rosterList ?? this.rosterList,
      leaveList: leaveList ?? this.leaveList,
    );
  }
}

// 状态逻辑处理类
class RosterNotifier extends StateNotifier<RosterState> {
  RosterNotifier() : super(RosterState(
    rosterList: ['张三', '李四', '王五'],
    leaveList: [],
  ));

  void addLeave(String name) {
    if (state.rosterList.contains(name)) {
      final newRoster = List<String>.from(state.rosterList)..remove(name);
      final newLeave = List<String>.from(state.leaveList)..add(name);
      state = state.copyWith(rosterList: newRoster, leaveList: newLeave);
    }
  }

  void cancelLeave(String name) {
    if (state.leaveList.contains(name)) {
      final newLeave = List<String>.from(state.leaveList)..remove(name);
      final newRoster = List<String>.from(state.rosterList)..add(name);
      state = state.copyWith(rosterList: newRoster, leaveList: newLeave);
    }
  }
}

// 全局状态Provider
final rosterProvider = StateNotifierProvider<RosterNotifier, RosterState>((ref) {
  return RosterNotifier();
});

3. MainScreen 转换(ConsumerWidget)

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'leave_page.dart';

class MainScreen extends ConsumerWidget {
  const MainScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 监听状态变化,自动刷新UI
    final rosterState = ref.watch(rosterProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('排班列表')),
      body: ListView.builder(
        itemCount: rosterState.rosterList.length,
        itemBuilder: (context, index) {
          final name = rosterState.rosterList[index];
          return ListTile(
            title: Text(name),
            trailing: ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => LeavePage(name: name),
                  ),
                );
              },
              child: const Text('申请请假'),
            ),
          );
        },
      ),
    );
  }
}

4. LeavePage 转换

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'roster_notifier.dart';

class LeavePage extends ConsumerWidget {
  final String name;
  const LeavePage({super.key, required this.name});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 仅获取状态操作类,不监听状态变化
    final rosterNotifier = ref.read(rosterProvider.notifier);

    return Scaffold(
      appBar: AppBar(title: const Text('申请请假')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('确认${name}请假吗?'),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                rosterNotifier.addLeave(name);
                Navigator.pop(context);
              },
              child: const Text('确认请假'),
            ),
            const SizedBox(height: 10),
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('取消'),
            ),
          ],
        ),
      ),
    );
  }
}

5. 全局配置ProviderScope

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'main_screen.dart';

void main() {
  runApp(
    // 全局状态容器,替代原ChangeNotifierProvider
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: const MainScreen(),
    );
  }
}

三、核心转换要点

  • 状态容器替换:用ProviderScope全局包裹App,单个状态用StateNotifierProvider定义
  • 状态更新逻辑:原notifyListeners()替换为直接赋值state = newState,需通过copyWith生成不可变新状态
  • 页面状态消费:原Consumer/Provider.of替换为ConsumerWidget+ref.watch(监听状态)或ref.read(仅获取操作类)
  • 状态设计规范:Riverpod强制状态不可变,需通过复制方法生成新状态,避免直接修改原数据

内容的提问来源于stack exchange,提问作者Pannam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 21:50:22