用于局部和全局变量的 Flutter Riverpod

Flutter Riverpod for local and global variables

我有两个文本编辑控制器,我正在尝试为这些文本编辑控制器提供从 api 获取的初始值。我需要全局声明文本编辑控制器并从 api 中给出初始值,所以我需要的是对全局变量使用 data3.firstName 和 data3.lastName,如果我尝试声明构建它的变量和函数不起作用,所以只需要将获取的数据用于全局文本编辑控制器,这样我就可以给出初始值。

late Future<Response> futureData;

  @override
  void initState() {
    super.initState();
    futureData = fetchAccountData();
  }

  final _formKey = GlobalKey<FormState>();

  TextEditingController editedFirstName =
      TextEditingController(text: 'Hello'); // needs to be data3.firsName
  TextEditingController editedLastName = TextEditingController(text: 'Riverpod looks great');// needs to be data3.lastName

  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) {}
  }

  @override
  Widget build(BuildContext context) {
    var height = MediaQuery.of(context).size.height;
    var width = MediaQuery.of(context).size.width;

    return SafeArea(
      child: WillPopScope(
        onWillPop: () async {
          Navigator.pushReplacement(
            context,
            MaterialPageRoute(
              builder: (context) => const ProfileScreen(),
            ),
          );
          return shouldPop;
        },
        child: KeyboardDismisser(
          gestures: const [
            GestureType.onTap,
            GestureType.onPanUpdateDownDirection
          ],
          child: Form(
            key: _formKey,
            child: Scaffold(
                resizeToAvoidBottomInset: false,
                appBar: AppBar(
                  backgroundColor: Colors.blue,
                  title: const Text(
                    'Edit My Profile',
                    style: TextStyle(
                        color: Colors.white, fontWeight: FontWeight.bold),
                  ),
                  leading: IconButton(
                    icon: const Icon(Icons.arrow_back),
                    onPressed: () {
                      Navigator.pushReplacement(
                        context,
                        MaterialPageRoute(
                          builder: (context) => const ProfileScreen(),
                        ),
                      );
                    },
                  ),
                ),
                body: FutureBuilder<Response>(
                  future: futureData,
                  builder: (context, snapshot) {
                    if (snapshot.hasData) {
                      AccountData data3 = AccountData.fromJson(
                        json.decode(snapshot.data!.body),
                      );

                      return Column(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        children: [
                          Container(
                            width: width,
                            height: height / 1.9,
                            decoration: BoxDecoration(
                              border: Border.all(
                                color: Colors.black,
                                width: 3,
                              ),
                            ),
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                              children: [
                                Row(
                                  children: [
                                    const Padding(
                                      padding: EdgeInsets.all(30),
                                      child: Text(
                                        "First Name:",
                                        style: TextStyle(
                                            fontSize: 20,
                                            fontWeight: FontWeight.bold),
                                      ),
                                    ),
                                    const Spacer(),
                                    Padding(
                                      padding: const EdgeInsets.all(30),
                                      child: SizedBox(
                                        width: width / 2.5,
                                        child: Center(
                                          child: TextFormField(
                                            textAlignVertical:
                                                TextAlignVertical.center,
                                            //initialValue: editedFirstName.text = data3.firstName,
                                            controller: editedFirstName,
                                            // ..selection =
                                            //     TextSelection.collapsed(
                                            //         offset: data3
                                            //             .firstName.length),
                                            decoration: InputDecoration(
                                              contentPadding:
                                                  const EdgeInsets.symmetric(
                                                      vertical: 10.0,
                                                      horizontal: 10.0),
                                              border: OutlineInputBorder(
                                                borderRadius:
                                                    BorderRadius.circular(10),
                                                borderSide: const BorderSide(
                                                    color: Colors.red,
                                                    width: 1),
                                              ),
                                            ),
                                            style: const TextStyle(
                                              fontSize: 17,
                                              fontWeight: FontWeight.bold,
                                            ),
                                            // inputFormatters: [
                                            //   LengthLimitingTextInputFormatter(15)
                                            // ],
                                            validator: (value) {
                                              if (value == null ||
                                                  value.isEmpty) {
                                                return 'Name is required';
                                              }
                                              return null;
                                            },
                                          ),
                                        ),
                                      ),
                                    ),
                                  ],
                                ),
                                Row(
                                  children: [
                                    const Padding(
                                      padding: EdgeInsets.all(30),
                                      child: Text(
                                        'Last Name:',
                                        style: TextStyle(
                                          fontSize: 20,
                                          fontWeight: FontWeight.bold,
                                        ),
                                      ),
                                    ),
                                    const Spacer(),
                                    Padding(
                                      padding: const EdgeInsets.all(30),
                                      child: SizedBox(
                                        width: width / 2.5,
                                        child: TextFormField(
                                          //initialValue: editedLastName.text = data3.lastName,
                                          controller: editedLastName,
                                          // ..selection =
                                          //     TextSelection.collapsed(
                                          //         offset:
                                          //             data3.lastName.length),
                                          decoration: InputDecoration(
                                            contentPadding:
                                                const EdgeInsets.symmetric(
                                                    vertical: 10.0,
                                                    horizontal: 10.0),
                                            border: OutlineInputBorder(
                                              borderRadius:
                                                  BorderRadius.circular(10),
                                            ),
                                          ),
                                          style: const TextStyle(
                                              fontSize: 17,
                                              fontWeight: FontWeight.bold),
                                        ),
                                      ),
                                    ),
                                  ],
                                ),

您似乎想为 TextField 提供初始值,但该值是从服务器异步获取的。

您使用 TextEditingController 的方向是正确的,但是由于您一开始没有准备好值,因此在创建控制器时不应使用 TextEditingController(text: 'Hello')

相反,您可以创建一个没有默认值的控制器,例如:final _controller = TextEditingController()。然后在你得到数据之后,比如在 initState 中调用 fetchAccountData() 方法后,你可以使用 _controller.text = fetchedValue.

将数据分配给控制器

我看到你也在使用 FutureBuilder。根据加载“默认值”之前要显示的内容,您可能需要也可能不需要 FutureBuilder

快速演示:

class QuickDemo extends StatefulWidget {
  const QuickDemo({Key? key}) : super(key: key);

  @override
  _QuickDemoState createState() => _QuickDemoState();
}

class _QuickDemoState extends State<QuickDemo> {
  final _controller = TextEditingController();

  @override
  void initState() {
    super.initState();
    _fetchData();
  }

  _fetchData() async {
    // do your network call here
    await Future.delayed(const Duration(seconds: 1));
    // and then parse your response here
    final data = 'Hello';
    // eventually you will have data, so assign it:
    _controller.text = data;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: TextField(
          controller: _controller,
        ),
      ),
    );
  }
}