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

Flutter Web Navigator 2.0刷新后数据丢失问题求助

问题根源

Web端刷新时,RouterDelegate会被重新实例化,内存中的setup、createAccountData等状态会全部丢失。而setNewRoutePath方法会根据当前路由信息重建状态,但你当前的路由信息未包含表单数据,因此导致状态被重置。

解决方案

方案一:用本地存储持久化临时表单数据

适合存储密码这类敏感数据,且不会将数据暴露在URL中。

  1. 添加依赖
    在pubspec.yaml中引入本地存储库:
dependencies:
  shared_preferences: ^2.2.2
  1. 初始化时恢复状态
    在RouterDelegate的initState中读取本地存储的临时数据:
@override
void initState() {
  super.initState();
  _restoreTempAccountData();
}

Future<void> _restoreTempAccountData() async {
  final prefs = await SharedPreferences.getInstance();
  // 恢复setup状态
  setup = prefs.getBool('setup') ?? false;
  // 恢复表单字段
  final name = prefs.getString('account_name');
  final email = prefs.getString('account_email');
  final telephone = prefs.getString('account_telephone');
  final password = prefs.getString('account_password');
  final country = prefs.getString('account_country');

  if (name != null && email != null && telephone != null && password != null && country != null) {
    createAccountData = {
      'name': name,
      'email': email,
      'telephone': telephone,
      'password': password,
      'country': country,
    };
  }
  notifyListeners();
}
  1. 提交时保存状态
    修改_handleSetUpTapped方法,将表单数据存入本地存储:
void _handleSetUpTapped(Map<String, String?> data) async {
  setup = true;
  createAccountData = data;
  final prefs = await SharedPreferences.getInstance();
  // 保存状态和表单数据
  await prefs.setBool('setup', true);
  await prefs.setString('account_name', data['name']!);
  await prefs.setString('account_email', data['email']!);
  await prefs.setString('account_telephone', data['telephone']!);
  await prefs.setString('account_password', data['password']!);
  await prefs.setString('account_country', data['country']!);
  notifyListeners();
}
  1. 退出时清除临时数据
    在onPopPage或账户设置完成后,清理本地存储的临时数据:
onPopPage: (route, result) async {
  if (!route.didPop(result)) {
    return false;
  }
  createAccount = false;
  setup = false;
  createAccountData.clear();
  // 清除本地存储
  final prefs = await SharedPreferences.getInstance();
  await prefs.remove('setup');
  await prefs.remove('account_name');
  await prefs.remove('account_email');
  await prefs.remove('account_telephone');
  await prefs.remove('account_password');
  await prefs.remove('account_country');
  notifyListeners();
  return true;
},

方案二:将非敏感表单数据与路由信息绑定

适合无需保密的字段(如姓名、邮箱),通过URL参数传递状态,刷新时从URL解析恢复数据(密码等敏感数据必须用方案一存储)。

  1. 定义路由配置类与解析器
    创建支持解析账户设置参数的路由配置和解析器:
// 路由配置基类
abstract class AppRouteConfig {}

// 登录路由配置
class LoginRouteConfig extends AppRouteConfig {}

// 账户设置路由配置
class SetupRouteConfig extends AppRouteConfig {
  final String? name;
  final String? email;
  final String? telephone;
  final String? country;

  SetupRouteConfig({this.name, this.email, this.telephone, this.country});
}

// 路由信息解析器
class AppRouteInformationParser extends RouteInformationParser<AppRouteConfig> {
  @override
  Future<AppRouteConfig> parseRouteInformation(RouteInformation routeInformation) async {
    final uri = Uri.parse(routeInformation.location!);
    if (uri.path == '/setup') {
      // 从URL参数中提取非敏感数据
      return SetupRouteConfig(
        name: uri.queryParameters['name'],
        email: uri.queryParameters['email'],
        telephone: uri.queryParameters['telephone'],
        country: uri.queryParameters['country'],
      );
    }
    return LoginRouteConfig();
  }

  @override
  RouteInformation restoreRouteInformation(AppRouteConfig configuration) {
    if (configuration is SetupRouteConfig) {
      // 将非敏感数据拼接成URL
      return RouteInformation(
        location: '/setup?name=${configuration.name}&email=${configuration.email}&telephone=${configuration.telephone}&country=${configuration.country}',
      );
    }
    return RouteInformation(location: '/login');
  }
}
  1. 从路由配置恢复状态
    修改RouterDelegate的setNewRoutePath方法,根据路由配置重建状态:
@override
Future<void> setNewRoutePath(AppRouteConfig configuration) async {
  if (configuration is SetupRouteConfig) {
    createAccount = true;
    setup = true;
    // 从本地存储读取敏感的密码数据
    final prefs = await SharedPreferences.getInstance();
    final password = prefs.getString('account_password');
    createAccountData = {
      'name': configuration.name,
      'email': configuration.email,
      'telephone': configuration.telephone,
      'password': password,
      'country': configuration.country,
    };
  } else {
    createAccount = false;
    setup = false;
    createAccountData.clear();
  }
  notifyListeners();
}
  1. 提交时更新路由信息
    修改_handleSetUpTapped方法,更新路由信息并保存敏感数据:
void _handleSetUpTapped(Map<String, String?> data) {
  setup = true;
  createAccountData = data;
  // 保存密码到本地存储
  SharedPreferences.getInstance().then((prefs) {
    prefs.setString('account_password', data['password']!);
  });
  // 更新路由信息,触发状态同步
  setNewRoutePath(SetupRouteConfig(
    name: data['name'],
    email: data['email'],
    telephone: data['telephone'],
    country: data['country'],
  ));
}
关键注意事项
  • 敏感数据(如密码)绝对不能放入URL,必须用本地存储或其他安全方式保存
  • 完成账户设置或返回登录页时,务必清除临时存储的数据,避免数据残留
  • Navigator 2.0的核心是路由状态与RouterDelegate状态同步,优先让状态由RouteInformation驱动,确保刷新、前进后退时状态一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 17:51:18