buttonsrtoys
buttonsrtoys

Reputation: 2771

How to use same generic type in StatefulWidget and State widget?

Below is a code mock-up for generic StatefulWidget that uses a FutureBuilder. I get the following error when FutureBuilder instantiates:

type '(User) => Future<List<User>>' is not a subtype of type '(dynamic) => Future<List<dynamic>>'

I suspect the error is the compiler wouldn't know that T and U are the same, so U is declared as dynamic while T as User? How would I change this code so the type used for the generic in the StatefulWidget is passed to State widget?

Widget build(BuildContext context) => TestWidget<User>();


class TestWidget<T> extends StatefulWidget {
  final Future<List<T>> Function(T) myFunc = (_) => Future<List<T>>(null);

  @override
  _TestState<T> createState() => _TestState<T>();
}

class _TestState<U> extends State<TestWidget> {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<U>>(
        future: widget.myFunc(null),
        builder: (context, snapshot) {
          return Container();
        });
  }
}

Upvotes: 1

Views: 1143

Answers (2)

icnahom
icnahom

Reputation: 76

You can see how FutureBuilder solved this issue. Instead of writing a return type of _TestState<T> for the createState() method, you would write State<TestWidget<T>>.

 State<TestWidget<T>> createState() => _TestState<T>();

Upvotes: 2

buttonsrtoys
buttonsrtoys

Reputation: 2771

I ended up effectively creating a second build() function in the StatefulWidget class that uses the T generic. It gets called from the build() in the State class. That way the State class doesn't care about the generics. I would have switched to a StatelessWidget with managed states, but I need to use AutomaticKeepAliveClientMixin, so had to stick with a StatefulWidget. My actual State class uses the mixin and has a bit more going on.

class TestWidget<T> extends StatefulWidget {
  final Future<List<T>> Function(T) myFunc = (_) => Future<List<T>>(null);

  Widget build(BuildContext context) {
    return FutureBuilder<List<T>>(
        future: myFunc(null),
        builder: (context, snapshot) {
          return Container();
        });
  }

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

class _TestState extends State<TestWidget> {
  @override
  Widget build(BuildContext context) {
    return widget.build(context);
  }
}

Upvotes: 0

Related Questions