🔄

FlutterにおけるuseEffectとFutureの使い分け

2024/10/10に公開

はじめに

自分自身はWebエンジニア出身でFlutterでの開発経験はほぼ皆無なのですが、個人的に最近Flutterの勉強を始めています。

今回はFlutterで非同期処理を実装する方法について調べてみました。

同期処理と非同期処理

同期処理とは「前の処理が完了するのを待ってから次の処理を行う処理」で、
非同期処理は「前の処理を待たず、各々独立して同時に処理を行う処理」のことです。

ネットワーク経由でのデータ取得やDBへの書き込み処理などユーザーを待たせてしまうような時間がかかる処理は非同期処理で扱ったりします。

Futureとは何か

Dart(Flutter)では非同期処理を実現する方法としてFuture・Stream・Isolateの3つがあります。

一番基本的な方法がFutureとasync/awaitを使った方法で公式でもまず最初に紹介されています。

await/asyncを書くことで非同期処理の完了を待ってから、結果を返すことができます。

Futureは非同期処理を実装するためにDartが提供している一機能です。JavaScript等の言語ではPromiseと呼ばれる機能に近いです。

Future<String> createOrderMessage() async {
  var order = await fetchUserOrder();
  return 'Your order is: $order';
}

Future<String> fetchUserOrder() =>
    // Imagine that this function is
    // more complex and slow.
    Future.delayed(
      const Duration(seconds: 2),
      () => 'Large Latte',
    );

Future<void> main() async {
  print('Fetching user order...');
  print(await createOrderMessage());
}

Streamは名の通りで、一度だけではなく継続的に非同期にデータを取得するような実装に使われます。リアルタイムのチャットアプリなど、常にデータの監視が必要なユースケースになります。

ちなみにFutureとStreamは並行処理であり、並列処理を行うことはできません。それを解決するのがIsolateなわけですが、並行処理と並列処理についてはまた別途まとめたいと思います。

useEffectとは何か

useEffectといえば、Reactの代表的なhooksであり、コンポーネントの初期化処理に使うイメージがあると思います。Flutterではflutter_hooksというパッケージを導入することで、同様の機能を持ったuseEffectを使うことができます。

useEffectは非同期処理と組み合わせて使われることが多いですが、useEffectは別に非同期処理を行うためのものではなく、ウィジェットのライフサイクルに関連した副作用の処理を管理する機能です。

具体的にはウィジェットの初回描画・または特定の値が更新された際に呼び出す処理を記載することができます。そのため、Futureと組み合わせて使われたりします。

Future<String> fetchUserData() async {
  await Future.delayed(Duration(seconds: 2));
  return 'John Doe';
}

class UserProfileWidget extends HookWidget {
  
  Widget build(BuildContext context) {
    final userName = useState<String?>(null);

    useEffect(() {
      fetchUserData().then((name) => userName.value = name);
      return null;
    }, []); // 空の依存配列で、マウント時に一度だけ実行

    return Text(userName.value ?? 'Loading...');
  }
}

useEffectとFutureの使い分け

useEffectとFutureの違いをざっくり表にまとめてみました。
ウィジェットのライフサイクル管理に使うのがuseEffectでFutureは純粋な非同期処理の関数ですね。

特性 useEffect Future
用途 ライフサイクルに関連した副作用の管理 一般的な非同期処理の実行と結果の取得
使用箇所 ウィジェット内で使用 どこでも使用可能(関数、クラスなど)
提供元 flutter_hooksパッケージが必要 Dartの標準ライブラリの一部

さいごに

今回はFlutterで非同期処理を実装する方法と関連してそうなuseEffectとFutureの使い分けについて見ていきました。これでAPIとの非同期処理を書く時のイメージがついたかと思います。

Discussion