【问题标题】:Flutter: How to access 'provider' values in a function outside the build context of the child widget?Flutter:如何在子小部件的构建上下文之外的函数中访问“提供者”值?
【发布时间】:2020-08-10 08:17:33
【问题描述】:

提供者值来自父窗口小部件。我可以在构建上下文下使用提供者值。但是我需要 getHomeCampaigns 函数中的提供者值。一旦构建了小部件,我尝试定义局部变量并将它们分配给提供程序值,但该函数声称这些变量是在 null 上调用的。我猜它们是在提供者的构建上下文下设置之前被使用的。

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // Variables to be set inside the function and then used by the last widget
  User currentUser;
  String country;
  List<CampaignWidget> friendsCamps;
  List<CampaignWidget> featuredCamps;

  // Function that needs the provider values
  getHomeCampaigns() async {
    // Get all campaigns where their owner is in the list of friends for the current user
    QuerySnapshot friendsSnapshot = await Firestore.instance
        .collection('campaigns')
        .where('user.uid', whereIn: currentUser.friends)
        .where('attributes.active', isEqualTo: true)
        .orderBy('created', descending: true)
        .limit(20)
        .getDocuments();
    // Get featured campaigns documents in the current country
    QuerySnapshot featuredSnapshot = await Firestore.instance
        .collection('campaigns')
        .where('attributes.featured', isEqualTo: true)
        .where('funders.${currentUser.uid}', isEqualTo: false)
        .where('country', isEqualTo: country)
        .orderBy('user.rating', descending: true)
        .limit(5)
        .getDocuments();
    // Make 2 lists of CampaignWidget out of the documents retrieved
    List<CampaignWidget> campaigns = friendsSnapshot.documents
        .map((doc) => CampaignWidget(campaign: Campaign.fromDocument(doc)))
        .toList();
    List<CampaignWidget> featured = featuredSnapshot.documents
        .map((doc) => CampaignWidget(campaign: Campaign.fromDocument(doc)))
        .toList();
    setState(() {
      // Set the featured and friends lists of CampaignWidget to the newly made lists
      this.featuredCamps = featured;
      this.friendsCamps = campaigns;
    });
  }

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

  @override
  Widget build(BuildContext context) {
    this.currentUser = Provider.of<User>(context);
    this.country = Provider.of<String>(context);
    return Scaffold(
      backgroundColor: Color(0xFFE8E8E8),
      appBar: AppBar(
        centerTitle: false,
        title: Text("Home"),
        actions: <Widget>[
          /// Search users
          IconButton(
            icon: Icon(
              Icons.search,
            ),
            onPressed: () {},
          ),
        ],
      ),
      body: RefreshIndicator(
        onRefresh: () => getHomeCampaigns(),
        child: // Some widget that uses the variables,
      ),
    );
  }
}

【问题讨论】:

    标签: flutter dart provider


    【解决方案1】:

    您可以像这样从您的提供程序读取变量:Provider.of(context, listen: false).yourVariable in getHomeCampaigns。您必须拥有 listen: false 才能使其正常工作,因为它不在小部件树中,因此无论何时 yourVariable 更改它都无法更新 - 请参阅 .如果这不起作用,则在您声明您的提供者时会出现问题。如果可行,请投票并接受作为答案,否则请在下方评论。

    【讨论】:

    • 我们可以在初始化它的提供者的上下文之外访问吗
    • @akashmaurya 不,他们必须是您上下文之上的提供者才能使用它。
    • 或者我们必须创建新的提供者,其值类似于 ChangeNotifierProvider.value()
    • 不建议在Provider.value()下新建provider
    • 在创建的提供者的上下文之外
    【解决方案2】:

    我的 api 从作为一个继承的小部件转移到一个提供者。 “The Flutter Complete Reference”建议避免由于复杂性而使用inheritWidget。我从 materialapp 开始,将它包裹在我的 api 类中,其中包含我的 restful 调用。我使用计数器查看按钮已被按下。现在,我可以在 materialapp 树中的所有对象中访问我的 api 调用。

    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    return MaterialApp(
        title: 'My app',
        theme: ThemeData(
             primarySwatch: Colors.blue,
        ),
        debugShowCheckedModeBanner: false,
        home: Provider<Api>(
            create: (context) => Api(),
            child: Home(title: 'my title')));
      }
    }
    
    class Home extends StatefulWidget {
     Home({Key key, @required this.title}) : super(key: key);
     final String title;
     @override
     _HomeState createState() => _HomeState();
     }
    
    class _HomeState extends State<Home> {
     int _counter = 0;
     onLogin(BuildContext context) {
       LoginView param = new LoginView("abc@com",
        "xxx");
    
       Provider.of<Api>(context, listen: false)
          .addLogin(context, param)
        .then((value) {
        setState(() {
        _counter++;
        });
       }).catchError((error) {
        DialogCaller.showErrorDialog(context, 
    error.toString()).then((value) {});
    });
    }
    
     @override
     Widget build(BuildContext context) {
      return Scaffold(
            appBar: AppBar(
              title: const Text('Example'),
            ),
            body: Container(
                child: Column(
              children: [
                TextButton.icon(
                    label: Text("abc"),
                    icon: Icon(Icons.web),
                    onPressed: () {
                      onLogin(context);
                      setState(() {
                        _counter++;
                      });
                    }),
                Text(
                  '$_counter',
                  style: 
     Theme.of(context).textTheme.headline4,
                )
              ],
            )));
     }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-02-20
      • 1970-01-01
      • 1970-01-01
      • 2021-11-13
      • 2020-01-17
      • 1970-01-01
      • 2020-03-22
      • 2022-11-15
      • 1970-01-01
      相关资源
      最近更新 更多