gql-dart / ferry

Stream-based strongly typed GraphQL client for Dart
https://ferrygraphql.com/
MIT License
602 stars 116 forks source link

Simple example calling a mutation on click and handling the response #602

Open simplenotezy opened 4 months ago

simplenotezy commented 4 months ago

I am playing around with mutations and would like to have a simple flutter widget that has a button.

When that button is pressed the mutation will be fired, and the button should show a loading state.

It is not clear to me, having been in and out of the documentation and github issues on how to accomplish this.

Can somebody help me in the right direction?

Here me fumbling around in the dark:

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});
  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  GAnalyzeImageReq uploadRequest = GAnalyzeImageReq(
    (b) => b
      ..vars.base64 = '123' // As a hot-fix, I'm setting a dummy value here
      ..executeOnListen = false,
  );

  @override
  initState() {
    super.initState();

    // ideally I wish to listen to the stream here
    // and do something with the data depending if it's an error or not
  }

  @override
  Widget build(BuildContext context) {
    return FerryClientProvider(
      child: (ferryClient) => Expanded(
        child: Align(
          alignment: Alignment.center,
          child: FerryOperation(
            request: uploadRequest,
            builder: (context, response, error) {
              if (response != null && response.data != null) {
                final data = response.data!.analyzeImage;

                if (data != null) {
                  // now I have data, do something with it
                }
              }

              return AnalyzeImageButton(
                isLoading: response?.loading == true,
                onPressed: () async {
                  uploadRequest = uploadRequest.rebuild(
                    (b) => b..vars.base64 = base64Image,
                  );

                  ferryClient.requestController.add(uploadRequest);
                },
              );
            },
          ),
        ),
      ),
    );
  }
}

class FerryClientProvider extends ConsumerWidget {
  final Widget Function(Client client) child;

  const FerryClientProvider({super.key, required this.child});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final ferry = ref.watch(ferryProvider);

    return ferry.when(
      data: child,
      error: (error, stackTrace) {
        return Text('Error: $error');
      },
      loading: () {
        return const CircularProgressIndicator();
      },
    );
  }
}
simplenotezy commented 3 months ago

@knaeckeKami I know you're probably very busy, but if you ever get a few minutes, I would love your input on this one

knaeckeKami commented 3 months ago

Did you check https://ferry.gql-dart.dev/docs/flutter-operation-widget#usage-with-mutations ?

If yes, is there anything concrete you have question for?

simplenotezy commented 3 months ago

Yes thank @knaeckeKami - I did review the whole documentation. Still, from that, it's not quite easy for me to understand how I can fire a single request on submit

knaeckeKami commented 3 months ago

You can execute final resultFuture = client.request(yourMutationReq).first to execute the request and get a future that resolves when the response is there (or an error happens)

simplenotezy commented 3 months ago

Interesting, thanks @knaeckeKami - I'll look into it again when working on the project, and report back. Thanks!

simplenotezy commented 3 months ago

@knaeckeKami If it's awaited, will the loading state also be maintained? E.g. a prop on the button.

knaeckeKami commented 3 months ago

you'll need to use basic state management approaches (setState, FutureBuilder...) for that.