Flutter Hooks and async calls

Issue

some noob questions ahead.

I’m using Flutter Hooks in my app, but struggling when trying to use hooks with calls that are async.

For example, how to get SharedPreferences through useMemoized (or any other async data with hooks)?

SharedPreferences preferences = useMemoized(() async => await SharedPreferences.getInstance());

The code above do not work because "The argument type ‘Future Function()’ can’t be assigned to the parameter type ‘SharedPreferences Function()’.", but how to get it done?

I wish to store the SharedPreferences instanceto use to read and write values.


Showing below a real example of how do I get the job done, but I want to know if there is a better way.

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:location/location.dart';
import 'package:shared_preferences/shared_preferences.dart';

class LocationWidget extends HookWidget {
  const LocationWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final Location location = useMemoized(() => Location());
    final ValueNotifier<bool> isLocationEnabled = useState(false);
    final ValueNotifier<bool> isServiceEnabled = useState(false);
    final ValueNotifier<PermissionStatus> permissionStatus = useState(PermissionStatus.denied);

    useEffect(() {
      Future<void>.microtask(() async {
        final SharedPreferences preferences = await SharedPreferences.getInstance();
        isLocationEnabled.value = preferences.getBool('trackingEnabled') ?? false;

        isServiceEnabled.value = await location.serviceEnabled();
        permissionStatus.value = await location.hasPermission();
      });
    }, <Location>[location]);

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Text(
          'Location',
          style: Theme.of(context).textTheme.headline6,
        ),
        const SizedBox(height: 5.0),
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            const Text('Tracking service'),
            Switch(
              value: isLocationEnabled.value,
              activeTrackColor: Colors.amberAccent,
              activeColor: Colors.amber,
              onChanged: (bool value) async {
                if (value) {
                  if (permissionStatus.value == PermissionStatus.denied) {
                    permissionStatus.value = await location.requestPermission();
                  }

                  if (permissionStatus.value == PermissionStatus.granted) {
                    if (!isServiceEnabled.value) {
                      isServiceEnabled.value = await location.requestService();
                    }

                    value = isServiceEnabled.value ? value : !value;
                  }
                }

                final SharedPreferences preferences = await SharedPreferences.getInstance();
                preferences.setBool('trackingEnabled', value);

                isLocationEnabled.value = value;
              },
            ),
          ],
        ),
      ],
    );
  }
}

Solution

I think your current code is enough, but if you want to use useMemoized I suggest this.

final future = useMemoized(SharedPreferences.getInstance);
final snapshot = useFuture(future, initialData: null);

useEffect(() {
  final preferences = snapshot.data;
  if (preferences == null) {
    return;
  }
  preferences.getBool('');
}, [snapshot.data]);

Answered By – jeiea

Answer Checked By – Mary Flores (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *