Skip to content

FutureSignal refresh() and reload() AsyncLoading status change does not match the API description #406

@lux-ok

Description

@lux-ok

I'm not sure if I understand this correctly. According to the instructions, refresh() maintains the state and only changes isLoading, so it shouldn't enter AsyncLoading. However, in my test code, both refresh and reload enter AsyncLoading, which is inconsistent with the instructions on the website https://dartsignals.dev/async/future/. Is this normal? If I've made any mistakes, please let me know. Thanks!

Version: signals_flutter 6.02

API description:

.refresh()
Refresh the future value by setting isLoading to true, but maintain the current state (AsyncData, AsyncLoading, AsyncError).

final s = futureSignal(() => Future(() => 1));
s.refresh();
print(s.value.isLoading); // true

.reload()
Reload the future value by setting the state to AsyncLoading and pass in the value or error as data.

final s = futureSignal(() => Future(() => 1));
s.reload();
print(s.value is AsyncLoading); // true

Test Code

// - lib/widgets/demo_exchange_rate_page.dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:signals_flutter/signals_flutter.dart';

typedef ExchangeRatesType = Map<String, double>;

final baseCurrency = signal<String>('HKD');
final exchangeRates = futureSignal(
  () => getRates(baseCurrency.value),
  debugLabel: 'exchangeRates',
);

class DemoExchangeRatePageTest extends StatelessWidget {
  final String title;
  const DemoExchangeRatePageTest({super.key, this.title = 'exchange_rate'});

  @override
  Widget build(BuildContext context) {
    final state = exchangeRates.watch(context);

    final heading = Row(
      spacing: 16,
      children: [
        Text(
          title,
          style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
        ),
        Spacer(),
        TextButton(
            onPressed: exchangeRates.refresh, child: const Text('REFRESH')),
        TextButton(
            onPressed: exchangeRates.reload, child: const Text('RELOAD')),
      ],
    );

    Widget content = switch (state) {
      AsyncError<ExchangeRatesType> e => Text(e.error.toString()),
      AsyncLoading<ExchangeRatesType> _ =>
        const Center(child: CircularProgressIndicator()),
      AsyncData<ExchangeRatesType> d => SingleChildScrollView(
          padding: const EdgeInsets.all(16),
          child: Text(d.value.toString()),
        ),
    };

    return Column(
      children: [
        Padding(padding: const EdgeInsets.all(16.0), child: heading),
        Expanded(child: content),
      ],
    );
  }
}

Future<Map<String, double>> getRates(String base) async {
  // - https://frankfurter.dev/

  final uri = Uri.parse('https://api.frankfurter.dev/v1/latest?base=$base');
  final res = await http.get(uri);

  if (res.statusCode == 200) {
    final data = jsonDecode(res.body);
    final rates = data['rates'] as Map<String, dynamic>; 
    final ratesMap = rates.map(
      (key, value) => MapEntry(key, (value as num).toDouble()),
    );
    return ratesMap;
  } else {
    throw Exception('Failed to load exchange rates: ${res.statusCode}');
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions