在Build方法外部创建的Future Builder内部创建的颤动使用变量, [英] Flutter use variable created inside Future builder outside of the build method,

查看:33
本文介绍了在Build方法外部创建的Future Builder内部创建的颤动使用变量,的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个将来的构建器,我使用它来获取数据,我需要将从API获得的使用到一个必须在build外部定义的文本编辑控制器,并且我需要给文本编辑控制器一个初始值,在这个初始值中,我需要放入data3.firstName和data3.lastName,因为现在初始值是硬编码的。

Future<Response> fetchAccountData() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  String? authorization = prefs.getString('authorization');
  var url = 'https://dev.api.wurk.skyver.co/api/v1/employees/account';

  response1 = await http.get(
    Uri.parse(url),
    headers: <String, String>{
      'authorization': authorization ?? basicAuth.toString()
    },
  );

  return response1;
}

factory AccountData.fromJson(Map<String, dynamic> json) {
    return AccountData(
        firstName: json['firstName'],
        lastName: json['lastName'],
        phoneNumber: json['phoneNumber']);
  }
}

Future<void> putAccountData() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String? authorization = prefs.getString('authorization');
    var url = 'https://dev.api.wurk.skyver.co/api/v1/employees/account';
    Map payload = {
      "firstName": editedFirstName.text,
      "lastName": editedLastName.text,
    };
    try {
      final response = await http.put(Uri.parse(url),
          headers: <String, String>{
            'authorization': authorization ?? basicAuth.toString(),
            "Content-Type": "application/json"
          },
          body: jsonEncode(payload));
    } catch (er) {}
  }

TextEditingController editedFirstName =
  TextEditingController(text: 'firstName'); << needs to be data3.firstName
  TextEditingController editedLastName =
  TextEditingController(text: 'lastName');<< needs to be data3.lastName

return SafeArea(
      child: WillPopScope(
        onWillPop: () async {
          Navigator.pushReplacement(
            context,
            MaterialPageRoute(
              builder: (context) => const ProfileScreen(),
            ),
          );
          return shouldPop;
        },

body: FutureBuilder<Response>(
                  future: futureData,
                  builder: (context, snapshot) {
                    if (snapshot.hasData) {
                      AccountData data3 = AccountData.fromJson( << data3 has data3.firstName, and 
                                                                                   data3.lastName
                        json.decode(snapshot.data!.body),
                      );

推荐答案

我不完全理解拥有全局文本控制器的原因(我也不认为这是一个好主意),但使用Riverpod时,它看起来会是这样的:

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

class AccountData {
  final String firstName;
  final String lastName;
  final String phoneNumber;
  
  AccountData({
    required this.firstName,
    required this.lastName,
    required this.phoneNumber,
  });
  
  factory AccountData.fromJson(Map<String, dynamic> json) {
    return AccountData(
      firstName: json['firstName'],
      lastName: json['lastName'],
      phoneNumber: json['phoneNumber'],
    );
  }
}

Future<Map<String, dynamic>> fetchAccountData() async {
  final response = {
    'firstName': 'Name',
    'lastName': 'LastName',
    'phoneNumber': '98786758690',
  };
  return Future.delayed(const Duration(seconds: 3), () => response);
}

final futureData = FutureProvider<AccountData>((_) async {
  final data = await fetchAccountData();
  return AccountData.fromJson(data);
});
  
final firstNameController = ChangeNotifierProvider<TextEditingController>((ref) {
  final controller = TextEditingController();
  ref.listen<AsyncValue<AccountData>>(futureData, (_, curr) {
    curr.whenOrNull(
      data: (d) => controller.text = d.firstName,
    );
  });
  
  return controller;
});

final lastNameController = ChangeNotifierProvider<TextEditingController>((ref) {
  final controller = TextEditingController();
  ref.listen<AsyncValue<AccountData>>(futureData, (_, curr) {
    curr.whenOrNull(
      data: (d) => controller.text = d.lastName,
    );
  });
  
  return controller;
});

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp();
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends ConsumerWidget {
  
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final firstController = ref.watch(firstNameController.notifier);
    final lastcontroller = ref.watch(lastNameController.notifier);
    return ref.watch(futureData).when(
      loading: () => const CircularProgressIndicator(),
      error: (e, _) => TextButton(
        child: Text('$e'),
        onPressed: () => ref.refresh(futureData),
      ),
      data: (_) {
        return Column(
          children: [
            TextField(
              controller: firstController,
            ),
            TextField(
              controller: lastcontroller,
            ),
          ]
        );
      }
    );
  }
}
现在,在Hazar Belge之后使用后期初始值设定项是一个好主意,如果没有状态管理,这个想法将是简单地使用FutureBuilder,然后将数据向下传递给StatefulWidget,后者使用该数据初始化TextEditingController,然后再次使用didUpdateWidget,所有这些都不依赖于外部包(您的应用程序越大,您将需要使用更多的包来帮助您快速开发,但我建议您尝试使用Basic来掌握您所能做的所有事情),所有这些都不依赖于外部包(您的应用程序越大,您就需要使用更多的包来帮助您快速开发,但我建议您尝试使用Basic来掌握您能做的所有事情

这篇关于在Build方法外部创建的Future Builder内部创建的颤动使用变量,的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆