質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

Q&A

解決済

1回答

2513閲覧

Flutter : 状態管理方法の選択、また、そもそも状態(state)を用意する必要があるのかの判断について

moriman

総合スコア615

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

0グッド

0クリップ

投稿2020/09/06 02:34

https://flutter.dev/docs/cookbook/networking/fetch-data
上記ページ最下部のComplete exampleなんですが、

全体的なつくりとして、

(1)
http通信で取得した文字列をfetchAlbum関数でAlbum型として取得(非同期なので
fetchAlbum関数の返り値はFuture<Album>型)

(2)
MyAppウイジェットをStatefullWidgetとして、MyAppStateクラスを用意、
そのMyAppStateクラスのフィールドして
Future<Album> futureAlbum;
を保持。つまりfutureAlbumが状態(state)。

(3)
MyAppStateクラスのbuildメソッド内でFutureBuilderウィジェットを使用。ということでFutureがコンプリートしたら得られたレスポンスのtitleフィールドを表示。

という感じだと思います。これ自体はこれで動いているので特に疑問は無いんですが、
これって状態としてfetchAlbum関数の返り値を保持する必要はあるのでしょうか?
つまりこのシンプルなケースならMyAppウィジェットはStatelessWidgetで、
FutureBuilderのfutureフィールドにfetchAlbum関数(の返り値)をセットする。つまり下記のコード。

import 'dart:async'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; Future<Album> fetchAlbum() async { final response = await http.get('https://jsonplaceholder.typicode.com/albums/19'); if (response.statusCode == 200) { // If the server did return a 200 OK response, // then parse the JSON. //return Album.fromJson(json.decode(response.body)); var temp=json.decode(response.body); return Album(userId:temp['userId'],id:temp['id'],title:temp['title']); } else { // If the server did not return a 200 OK response, // then throw an exception. throw Exception('Failed to load album:${response.statusCode}'); } } class Album { final int userId; final int id; final String title; Album({this.userId, this.id, this.title}); factory Album.fromJson(Map<String, dynamic> json) { return Album( userId: json['userId'], id: json['id'], title: json['title'], ); } } void main() => runApp(MyApp()); class MyApp extends StatelessWidget { MyApp({Key key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Fetch Data Example', theme: ThemeData( primarySwatch: Colors.blue, ), home: Scaffold( appBar: AppBar( title: Text('Fetch Data Example'), ), body: Center( child: FutureBuilder<Album>( future: fetchAlbum(), builder: (context, snapshot) { if (snapshot.hasData) { return Text(snapshot.data.title); } else if (snapshot.hasError) { return Text("${snapshot.error}"); } // By default, show a loading spinner. return CircularProgressIndicator(); }, ), ), ), ); } }

これでstate有りの時と同様の結果が出るんですが、それならStatefulWidgetにする必要あるのか?と思ってしまいます。FutureBuilder使うときはstateを用意すべき、みたいなことがあるんでしょうか?

じゃなくて、今回はシンプルな例だからたまたまstate無しでも問題無いが、例えば

  • 一つのアプリ(画面)の中の複数の箇所(複数のウィジェット)で、取得したレスポンスを表示するなりしたい場合
  • ボタンを押したら別のアルバムを取得して表示するようにしたい場合

上記のような場合stateを用意すべきなので今回のサンプルでもstate有りのサンプルを示している、ということでしょうか。

もう一つ、Flutterの状態管理に関して、Bloc、Scoped Model、Provider、Riverpod、Hooks、Reduxなどいろいろなライブラリが次々と出てきて、どれを勉強すれば良いのかよくわかりません。
全部勉強しないといけないのでしょうか?全部って相当なコストだと思うのですが(笑)、
結局目的は全て「状態管理」なので同じことを方法を変えてやろうとしているわけですよね。どれかひとつが圧倒的に便利、ということならそれで決まりでしょうし、そうでないのなら、どれかの選択肢で目的達成(問題解決)できればいいのではないか、と思うのですが。

(Hooksについてはreactでもあったような気がしますが、
Flutter公式では採用しない?わかりませんが、いろいろな話がありますよね。)

一番最初からFlutterをやっている人は全部キャッチアップして、それぞれの利点もわかっている、という方もおられると思うのですが、最近勉強を始めた人だと、もうすでに
「今はProviderですよね」
「いやRiverpodですよね(でも現時点で公式推奨はProvider)」
「Blocは古いですよね」
などの声がtwitterなどで見られます。(私自身Blocも全くわかってないのですが)

こういうのはどういう風に捉えれば良いのでしょうか。
結局「道具」であり、最終的にどれが推奨されるかは全くわからないし、結局どれがいいのかは自分で使ってみなければわからないので、とにかくいろいろ使ってみて便利だと思うものを見つけて採用しながら今後の流れを注視する、みたいなことですかね?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

これでstate有りの時と同様の結果が出るんですが

表示されるデータは同じだと思いますが、サーバーにリクエストが飛ぶ回数が変わります。
例として挙げられているコードの場合だと、

  • statefullの場合: リクエストは最初の1回だけ(initStateで呼んだ分)。以降は保持されたstateが使われる。
  • statelessの場合: buildが呼ばれる度に毎回リクエストが走る。

となります。
試しにfetchAlbum関数にprint文を仕込んで何回かホットリロードしてみると違いがわかると思います。


Bloc、Scoped Model、Provider、Riverpod、Hooks、Reduxなどいろいろなライブラリが次々と出てきて、どれを勉強すれば良いのかよくわかりません。全部勉強しないといけないのでしょうか?

とりあえずProviderの使い方さえ覚えれば大抵のアプリは作れると思います。
また、アプリの要件によって多少の向き不向きはあるものの、最終的にどれがいいかは完全に好みの問題です。


結局「道具」であり、最終的にどれが推奨されるかは全くわからないし、結局どれがいいのかは自分で使ってみなければわからないので、とにかくいろいろ使ってみて便利だと思うものを見つけて採用しながら今後の流れを注視する、みたいなことですかね?

その通りだと思います。

投稿2020/09/06 10:31

nskhei

総合スコア704

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moriman

2020/09/06 14:57

回答をいただきましてありがとうございます。 ご指摘頂いた点なのですが、確かにコードのつくりからして、リクエストが飛ぶ回数が変わりますね。 Firebaseなどだと問い合わせ回数で料金が変わって来るので、どうでもいいことではないような気がするのですが、私自身具体的にいまいちここら辺のFlutterの仕組みがよくわかっていないような気がします。 Hot reloadした時に確かに問い合わせ回数が違うのですが、Hot reloadは結局開発時の機能なのでユーザーの行動とは関係無いですよね。 これも今回のシンプルなサンプルでは差は無いが、例えばボタンを押すごとに問い合わせる、というような場合 buildメソッドが実行されるたびに問い合わせるか、 最初のinitState()実行時のみの問い合わせか、 なので問い合わせ回数が変わってくる、ということですかね。 それくらい自分でコード書いて試してみたらいいじゃん、と言われるとそれはそうなんですが笑
moriman

2020/09/06 15:19

すみません、何となくでコメントしていましたが、 実際ボタンつけてみると、statefulWidgetの方は「ボタン押すとsetStateメソッドで状態にfetchAlbum()の返り値をセット」というよくあるコードが出来上がりましたが、 statelessWidgetの方はボタンを用意しても、押した時にどうするか、特にコードの書きようが無いですよね、状態(state)が無いので。 なので上記のコメントも答えようがないですね笑
nskhei

2020/09/07 02:12

ご返信ありがとうございます。 > Hot reloadは結局開発時の機能なのでユーザーの行動とは関係無いですよね。 buildメソッドは実際のアプリでも親Widgetの更新などで呼ばれますし、極端な例だと、アニメーションを使っていれば毎フレームごとに呼ばれたりします。
nskhei

2020/09/07 02:14

あと、ご指摘の通り、ボタンを押すごとに問い合わせるといった挙動はstatefullにするかproviderなどの状態管理を使うしか無いですね。
moriman

2020/09/11 00:03

ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問