rrousselGit / riverpod

A reactive caching and data-binding framework. Riverpod makes working with asynchronous code a breeze.
https://riverpod.dev
MIT License
6.17k stars 943 forks source link

UI not re-rendering when FutureProvider refreshed #399

Closed mohanasundaramn closed 3 years ago

mohanasundaramn commented 3 years ago

@rrousselGit I am using FutureProvider to fetch data from the network and using context.refresh(provider) to re-fetch data from the network when I do context.refresh(provider) network call made successfully and I am getting a response from the server but UI, not re-rendering. I am new riverpod I couldn't figure what is wrong.

class OutStandingService {
  final Dio _client;

  OutStandingService(this._client);

  Future<List<OutStandingModel>> fetchOutStandings(String searchTerm) async {
    final response = await _client.get("outstanding?search=$searchTerm");
    final outStandings = response.data['outStandings'];
    final result = OutStandingResponse.fromJson({'outStandings': outStandings});
    return result.outStandings;
  }
}
final outStandingServiceProvider = Provider<OutStandingService>(
  (ref) {
    return OutStandingService(appClient);
  },
);
final fetchOutStandings =
    FutureProvider.autoDispose.family<List<OutStandingModel>, String>(
  (ref, searchTerm) async {
    final outStandingService = ref.read(outStandingServiceProvider);
    final response = await outStandingService.fetchOutStandings(searchTerm);
    print(response);
    return response;
  },
);
import 'package:MyApp/outstandings/widgets/out_standing_card.dart';
import 'package:MyApp/providers/providers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

class OutstandingPage extends HookWidget {
  @override
  Widget build(BuildContext context) {  
    final outStandings = useProvider(fetchOutStandings(''));
    final isSearchTapped = useState(false);
    final controller = useTextEditingController();
    return Scaffold(
      appBar: AppBar(
        leading: isSearchTapped.value
            ? IconButton(
                icon: Icon(Icons.close),
                onPressed: () {
                  isSearchTapped.value = !isSearchTapped.value;
                  controller.text = "";
                },
              )
            : SizedBox(),
        title: AnimatedCrossFade(
          alignment: Alignment.topLeft,
          firstChild: Text("Outstandings"),
          secondChild: Container(
            padding: const EdgeInsets.only(left: 8),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(5),
              color: Colors.white,
            ),
            height: 36,
            child: TextField(
              controller: controller,
              decoration: InputDecoration(
                hintText: "Search customer by name/phone",
                border: InputBorder.none,
              ),
            ),
          ),
          crossFadeState: isSearchTapped.value
              ? CrossFadeState.showSecond
              : CrossFadeState.showFirst,
          duration: Duration(milliseconds: 250),
          firstCurve: Curves.easeIn,
          secondCurve: Curves.easeOut,
        ),
        actions: [
          IconButton(
            icon: Icon(Icons.search),
            onPressed: () {
              if (!isSearchTapped.value) {
                isSearchTapped.value = !isSearchTapped.value;
              } else {
                context.refresh(fetchOutStandings(controller.text));
              }
            },
          ),
        ],
      ),
      body: Container(
        child: outStandings.when(
          data: (response) => ListView.separated(
            separatorBuilder: (ctx, index) {
              return SizedBox(height: 5);
            },
            itemCount: response.length,
            itemBuilder: (ctx, index) {
              return OutStandingCard(outStanding: response[index]);
            },
          ),
          loading: () => Center(
            child: CircularProgressIndicator(),
          ),
          error: (err, stackTrace) {
            print(err);
            return Center(
              child: Text("Something went wrong, please try after sometimes"),
            );
          },
        ),
      ),
    );
  }
}
rrousselGit commented 3 years ago

You misused family

What happens is, your UI is listening to fetchOutStandings('') but you refreshed fetchOutStandings(controller.text) (which is most likely different from '')

What you likely want to do instead is:

Widget build(context) {
  final searchFilter = useState('');
  final outStandings = useProvider(fetchOutStandings(searchFilter.value));

  ...

  IconButton(
    icon: Icon(Icons.search),
    onPressed: () {
      searchFilter.value = controller.text;
    },
  ),
}
mohanasundaramn commented 3 years ago

@rrousselGit Thank you so much. now I understood the reason why it is not working. Your packages are really very much helpful I am using freeezed, riverpod, hooks. it makes my life easier. Thank you so much for your wonderful contribution to the community.