我的未来构建器返回错误,我不知道该怎么做

问题描述 投票:0回答:1

这是我的未来构建器,它返回一个错误,我认为这是因为 Riverpod,但我找不到解决方案。错误在底部 我尝试了changedDependency,但没有成功,我正常收到列表并且它显示在控制台中,但它没有显示在initState中。 我的目标是每当页面启动时都有自加载列表,但关于接收列表的数据处理一切都很好,并且 api 正在连接它,只是

snapshot.data
由于某种原因变成了 null。 这是我第一次使用这种类型的构建器,所以我希望我对此事足够清楚。

import 'dart:convert';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import '../models/account.dart';
import '../provider/company_provider.dart';
import '../provider/user_provider.dart';

class AccountFinder extends ConsumerStatefulWidget {
  const AccountFinder({super.key});

  @override
  ConsumerState<AccountFinder> createState() => _AccountFinderState();
}

class _AccountFinderState extends ConsumerState<AccountFinder> {
  late Future<List<Account>> accounts;
  String searchString = "";
  Future<List<Account>> fetchAccounts() async {
    var userID = ref.watch(userStateProvider).id;
    var companyID = ref.watch(companyStateProvider).comID;
    print(userID);
    final url = Uri.parse(
      'http://api_adress/GetAllActs?CID=$companyID',
    );
    final headers = {'Content-Type': 'application/json'};
    final response = await http.post(
      url,
      headers: headers,
      body: json.encode({
        "id": userID,
        "userName": "string",
        "password": "string",
        "loggedIn": true,
        "userActive": true,
        "userDeleteable": true
      }),
    );

    if (response.statusCode == 200) {
      List<dynamic> listAccountsJson = jsonDecode(response.body);

      return listAccountsJson
          .map((account) => Account.fromJson(account))
          .toList();
    } else {
      throw Exception('Failed to load items');
    }
  }

  @override
  void initState() {
    super.initState();
    accounts = fetchAccounts();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      mainAxisAlignment: MainAxisAlignment.start,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        SafeArea(
          child: Container(
            height: 40,
            decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(10),
                color: Theme.of(context)
                    .colorScheme
                    .onBackground
                    .withOpacity(0.1)),
            margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
            child: TextField(
              onTapOutside: (event) =>
                  FocusManager.instance.primaryFocus?.unfocus(),
              onChanged: (value) {
                setState(() {
                  searchString = value.toLowerCase();
                });
              },
              style: Theme.of(context).textTheme.bodyMedium!,
              decoration: InputDecoration(
                  border: InputBorder.none,
                  hintText: AppLocalizations.of(context)!.search,
                  hintStyle: Theme.of(context).textTheme.bodyMedium!.copyWith(
                      fontSize: 16,
                      fontWeight: FontWeight.w300,
                      color: Theme.of(context)
                          .colorScheme
                          .onBackground
                          .withOpacity(0.7)),
                  prefixIcon: const Icon(
                    Icons.search,
                  )),
            ),
          ),
        ),
        IconButton(onPressed: fetchAccounts, icon: Icon(Icons.abc)),
        const SizedBox(height: 10),
        Expanded(
          child: FutureBuilder(
            builder: (context, AsyncSnapshot<List<Account>> snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                return Center(child: CircularProgressIndicator());
              } else if (snapshot.hasError) {
                return Center(child: Text('Error: ${snapshot.error}'));
              } else if (!snapshot.hasData) {
                return Center(child: Text('No data available'));
              } else {
                return SingleChildScrollView(
                  child: ListView.separated(
                    padding: const EdgeInsets.all(8),
                    itemCount: snapshot.data!.length,
                    itemBuilder: (BuildContext context, int index) {
                      return snapshot.data![index].actName!
                              .toLowerCase()
                              .contains(searchString)
                          ? Card(
                              elevation: 3,
                              child: ListTile(
                                title: Text('${snapshot.data?[index].actName}'),
                                subtitle: Text(
                                    ' ${snapshot.data?[index].actMobileNo}\n${snapshot.data?[index].actPhoneNo}\n'),
                              ),
                            )
                          : Container();
                    },
                    separatorBuilder: (BuildContext context, int index) {
                      return snapshot.data![index].actName!
                              .toLowerCase()
                              .contains(searchString)
                          ? const Divider()
                          : Container();
                    },
                  ),
                );
              }
            },
            future: accounts,
          ),
        ),
      ],
    );
  }
}

这是我收到的错误:

dependOnInheritedWidgetOfExactType<UncontrolledProviderScope>() or dependOnInheritedElement() was called before _AccountFinderState.initState() completed.
I/flutter (14799): When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget.
I/flutter (14799): Typically references to inherited widgets should occur in widget build() methods. Alternatively, initialization based on inherited widgets can be placed in the didChangeDependencies method, which is called after initState and whenever the dependencies change thereafter.```


flutter listview flutter-futurebuilder
1个回答
0
投票

您收到的错误消息提供了有关问题的明确提示:

dependOnInheritedWidgetOfExactType<UncontrolledProviderScope>()

 完成之前调用了 
dependOnInheritedElement()
_AccountFinderState.initState()

Riverpod 提供程序所基于的继承小部件无法在

initState()
中访问。这是因为
initState()
在小部件完全集成到小部件树之前被调用,这意味着它还无法从其上方的小部件访问上下文。

这是根据错误的解决方案:

1.使用
didChangeDependencies

不要在

initState()
中获取数据,而是重写
didChangeDependencies()
方法,该方法在
initState()
之后以及每当依赖项(如提供程序)发生更改时立即调用:

@override
void didChangeDependencies() {
  super.didChangeDependencies();

  // Check if accounts is not already set or you can use another mechanism 
  // to ensure you don't call fetchAccounts() multiple times
  if (accounts == null) {
    accounts = fetchAccounts();
  }
}

注意:使用时请小心

didChangeDependencies()
。它可以在小部件的整个生命周期中被多次调用,特别是如果小部件依赖于多个 InheritedWidget(例如提供程序、主题等)。因此,您需要确保不会重复地重新获取数据。

2.从
initState()
删除通话:

您现在可以删除从

initState()
方法获取数据:

@override
void initState() {
  super.initState();
  // Remove accounts = fetchAccounts(); from here
}

通过进行此调整,您应该不再看到与访问

initState()
内的 Riverpod 提供程序(或任何 InheritedWidgets)相关的错误。

© www.soinside.com 2019 - 2024. All rights reserved.