AielloChan / query_client

A react hook like flutter request lib

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Query Client

More like react hook, but for Flutter.

Features

πŸ‘Ά Simple api request

final _queryClient = QueryClient<bool>(({data, dataList}) async {
  await Future.delayed(Duration(seconds: 1));
  return true;
});

Widget build() {
  /// use future
  return FutureBuilder(
    future: _queryClient.future,
    build: () {
      return Text("just work"),
    }
  );
}

πŸ‘¨β€πŸš€ Auto Update UI

final _queryClient = QueryClient<bool>(
  ({data, dataList}) async {
    await Future.delayed(Duration(seconds: 1));
    return true;
  },
  onUpdate: () {
    /// if you wanna auto update the UI
    /// just add this
    if (mounted) setState(() {});
  },
)

Widget build() {
  if (_queryClient.isLoading) {
    return Center(
      child: Text("Loading..."),
    );
  }

  if (_queryClient.isError) {
    print("[MyWidget] error ${_queryClient.error}");
    return GestureDetector(
      child: Center(
        child: Text("πŸ€• Something went wrong! Tap to retry"),
      ),
      onTap: () {
        /// retry
        _queryClient.request();
      }
    );
  }

  return Center(
    child: Text("πŸŽ‰ It works! ${_queryClient.data}"),
  );
}

πŸš€ Infinity Load (load more mode)

final _queryClient = QueryClient<bool>(
  ({data, dataList}) async {
    if (data != null) {
      /// you can use previousData to load next chunk of data
      /// such as get cursor from previousData or get pageId from previousData
      await Future.delayed(Duration(seconds: 1));
    } else {
      await Future.delayed(Duration(seconds: 1));
    }
    return true;
  },
  onUpdate: () {
    /// if you wanna auto update the UI
    /// just add this
    if (mounted) setState(() {});
  },
)

Widget build() {
  if (_queryClient.isLoading) {
    return Center(
      child: Text("Loading..."),
    );
  }

  if (_queryClient.isError) {
    print("[MyWidget] error ${_queryClient.error}");
    return GestureDetector(
      child: Center(
        child: Text("πŸ€• Something went wrong! Tap to retry"),
      ),
      onTap: () {
        /// retry
        /// will clean all loaded data, and request
        _queryClient.request();

        /// or you can just retry load more
        /// _queryClient.loadMore();
      }
    );
  }

  return GestureDetector(
    child: Center(
      child: Text("πŸŽ‰ It works! ${_queryClient.data}. Tap to load more."),
    ),
    onTap: () {
      /// load more data
      _queryClient.loadMore();
    }
  );
}

πŸ’‘ Mutate data

Some times we need mutate loaded data, such as user deleted one row, we should send DELETE request to the server, then fetch newest list back.

now you can use mutate to instantly change local data (you already have it in the data or dataList property of queryClient variable), then send DELETE request to the server, if success, just do noting (cos we already deleted that item); if request failed, just put the item back, and say "Uh oh, something went wrong, plz try again~" 🀣

let see how it works:

final _queryClient = QueryClient<bool>(
  ({data, dataList}) async {
    if (data != null) {
      /// you can use previousData to load next chunk of data
      /// such as get cursor from previousData or get pageId from previousData
      await Future.delayed(Duration(seconds: 1));
    } else {
      await Future.delayed(Duration(seconds: 1));
    }
    return true;
  },
  onUpdate: () {
    /// if you wanna auto update the UI
    /// just add this
    if (mounted) setState(() {});
  },
)

Widget build() {
  if (_queryClient.isLoading) {
    return Center(
      child: Text("Loading..."),
    );
  }

  if (_queryClient.isError) {
    print("[MyWidget] error ${_queryClient.error}");
    return GestureDetector(
      child: Center(
        child: Text("πŸ€• Something went wrong! Tap to retry"),
      ),
      onTap: () {
        /// retry
        /// will clean all loaded data, and request
        _queryClient.request();

        /// or you can just retry load more
        /// _queryClient.loadMore();
      }
    );
  }

  final list = data.list;

  return GestureDetector(
    child: Column(
      children: list.map(
        (x) {
          return GestureDetector(
            child: Text(x.name),
            onTap: () {
              /// just delete this item
              _queryClient.mutate(({data, dataList}) {
                /// delete data from previous data or dataList
                final originIndex = data.list.indexWhere((y) => y.id == x.id);
                final origin = data.list.removeAt(originIndex);

                /// and send request to server, you should change this code to your real call
                /// don't wait for future here, just leave the function return a future, to trigger upper change to UI.
                return Request.deleteItem(x.id)
                  .then((res) {
                    /// success just leave it be
                  })
                  .catchError((err) {
                    /// just put it back
                    data.list.insert(originIndex, origin);
                    /// and don't forget to say sorry
                    Toast.show("πŸ€• Something went wrong! Try again!");
                  })
              });
            }
          );
        },
      ),
    ),
    onTap: () {
      /// load more data
      _queryClient.loadMore();
    }
  );
}

Feedback welcome

aiello.chan@gmail.com

About

A react hook like flutter request lib

License:MIT License


Languages

Language:Dart 100.0%