0
votes

I fail to understand why my FutureProvider fails to whereas my ChangeNotifierProvider works perfectly.

No matter what I do, it gives me the same error, even if I remove my ChangeNotifierProvider and replace it with FutureProvider or wrap my MaterialApp widget with FutureProvider or user MultiProvider, it gives me the same error.

import 'package:provider/provider.dart';
import 'package:sprightly/new/Constants.dart';
import 'package:sprightly/new/ConstraintProvider.dart';
import 'package:sprightly/new/SearchBox.dart';
import 'package:sprightly/new/api/ApiService.dart';
import 'package:sprightly/new/model/ServerResponse.dart';
import 'package:sprightly/new/profile/Profile.dart';

class Home extends StatelessWidget {
  const Home({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: green,
        elevation: 0,
      ),
      body: Background(),
    );
  }
}

class Background extends StatelessWidget {
  double width(double width) {
    return width > 500 ? width * 0.6 : width;
  }

  void setConstraints(BuildContext context, BoxConstraints constraints) {
    Provider.of<Constraint>(context, listen: false)
        .setHeight(constraints.maxHeight);
    Provider.of<Constraint>(context, listen: false)
        .setWidth(constraints.maxWidth);
  }

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => Constraint(),
      child: LayoutBuilder(builder: (context, constraint) {
        setConstraints(context, constraint);
        return Stack(
          children: [
            Column(
              children: [
                Container(
                  width: double.infinity,
                  height: MediaQuery.of(context).size.height * 0.20,
                  color: green,
                  child: Align(
                    alignment: Alignment.centerRight,
                    child: Image.asset(
                      'assets/images/backdrop.svg',
                    ),
                  ),
                ),
              ],
            ),
            Center(
              child: Padding(
                padding: EdgeInsets.only(
                  top: MediaQuery.of(context).size.height * .10,
                ),
                child: ClipRRect(
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(30),
                    topRight: Radius.circular(30),
                  ),
                  child: Container(
                    width: width(constraint.maxWidth),
                    color: Color(0xffF0F0F0),
                    child: Foreground(),
                  ),
                ),
              ),
            ),
          ],
        );
      }),
    );
  }
}

class Foreground extends StatelessWidget {
  final ApiService api = ApiService();

  @override
  Widget build(BuildContext context) {
    return FutureProvider(
      create: (context) => api.getServer(),
      catchError: (context, error) => print(error.toString()),
      child: Column(
        children: [
          Padding(
            padding: const EdgeInsets.only(
              top: 20,
              left: 20,
              right: 20,
            ),
            child: SearchBox(),
          ),
          SizedBox(
            height: 10,
          ),
          ServerList(),
        ],
      ),
    );
  }
}

class ServerList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    ServerResponse response = Provider.of<ServerResponse>(context);

    return Expanded(
      child: ListView.builder(
          itemCount: response.response.length,
          itemBuilder: (context, index) {
            var width = Provider.of<Constraint>(context).getWidth();
            print(width);
            return Profile(index);
          }),
    );
  }
}

this is the error


Error: Could not find the correct Provider<ServerResponse> above this ServerList Widget

This likely happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:

- The provider you are trying to read is in a different route.

  Providers are "scoped". So if you insert of provider inside a route, then
  other routes will not be able to access that provider.

- You used a `BuildContext` that is an ancestor of the provider you are trying to read.

  Make sure that ServerList is under your MultiProvider/Provider<ServerResponse>.
  This usually happen when you are creating a provider and trying to read it immediatly.

  For example, instead of:

  
  Widget build(BuildContext context) {
    return Provider<Example>(
      create: (_) => Example(),
      // Will throw a ProviderNotFoundError, because `context` is associated
      // to the widget that is the parent of `Provider<Example>`
      child: Text(context.watch<Example>()),
    ),
  }
  

  consider using `builder` like so:

  
  Widget build(BuildContext context) {
    return Provider<Example>(
      create: (_) => Example(),
      // we use `builder` to obtain a new `BuildContext` that has access to the provider
      builer: (context) {
        // No longer throws
        return Text(context.watch<Example>()),
      }
    ),
  }
1

1 Answers

0
votes

I found the issue, it was a silly issue needed to provide the type when declaring the FutureProvider.

Just changed this:

class Foreground extends StatelessWidget {
  final ApiService api = ApiService();

  @override
  Widget build(BuildContext context) {
    return FutureProvider(
      create: (context) => api.getServer(),
      catchError: (context, error) => print(error.toString()),
      child: Column(
        children: [
          Padding(
            padding: const EdgeInsets.only(
              top: 20,
              left: 20,
              right: 20,
            ),
            child: SearchBox(),
          ),
          SizedBox(
            height: 10,
          ),
          ServerList(),
        ],
      ),
    );
  }
}

to this:

class Foreground extends StatelessWidget {
  final ApiService api = ApiService();

  @override
  Widget build(BuildContext context) {
    return FutureProvider<ServerResponse>(
      create: (context) => api.getServer(),
      catchError: (context, error) => print(error.toString()),
      child: Column(
        children: [
          Padding(
            padding: const EdgeInsets.only(
              top: 20,
              left: 20,
              right: 20,
            ),
            child: SearchBox(),
          ),
          SizedBox(
            height: 10,
          ),
          ServerList(),
        ],
      ),
    );
  }
}