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

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

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

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

Q&A

解決済

1回答

7753閲覧

Flutter、FutureBuilderとsetStateを両立させたい

matasaburo

総合スコア12

Flutter

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

0グッド

0クリップ

投稿2020/08/21 09:36

この間Flutterのデータ読み込みタイミングについて質問させていただきましたが、またわからないところが出たのでご教授いただけると助かります。
https://teratail.com/questions/285351

初期データ読み込みはFutureBuilderで行うといいという理解はできたのですが、FutureBuilder内のどこかでsetStateを行うとFutureBuilderの引数futureに渡されたメソッドが再び呼ばれてしまい、初期値が何度も代入されてしまうという問題に直面しました。

例えば下のようなコードがその例になります。

import 'package:flutter/material.dart'; class SetStateScreen extends StatefulWidget { @override _SetStateScreenState createState() => _SetStateScreenState(); } class _SetStateScreenState extends State<SetStateScreen> { Future<int> getData() async { // 何らかの非同期で初期値を取ってくる処理 int default_num = 0; // 取ってきた初期値を表す変数 return default_num; } @override Widget build(BuildContext context) { int x; return Container( color: Colors.white, child: FutureBuilder( future: getData(), builder: (BuildContext context, AsyncSnapshot<int> snapshot) { Widget childWidget; if (snapshot.hasData) { // futureBuilderでgetした初期値代入 // setStateの度に呼ばれ、初期値が何度も代入されてしまう。 x = snapshot.data; childWidget = Center( child: Container( child: FlatButton( onPressed: () { setState(() { x += 1; }); }, child: Text("$x"), )), ); } else { childWidget = Container(); } return childWidget; }), ); } }

こういう場合、例えば上のコードを正しく動かせる良い実装方法などありましたらご教授いただけると幸いです。

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

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

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

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

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

guest

回答1

0

ベストアンサー

FutureBuilderを使うなら、以下のような感じでどうでしょうか

dart

1class SetStateScreen extends StatefulWidget { 2 3 _SetStateScreenState createState() => _SetStateScreenState(); 4} 5 6class _SetStateScreenState extends State<SetStateScreen> { 7 int number; 8 9 Future<int> getData() async { 10 if (number == null) { 11 number = 0; // 実際は非同期でデータを取ってきて代入する 12 } 13 return number; 14 } 15 16 17 Widget build(BuildContext context) { 18 return Container( 19 color: Colors.white, 20 child: FutureBuilder<int>( 21 future: getData(), 22 builder: (context, snapshot) { 23 if (!snapshot.hasData || snapshot.data == null) { 24 return SizedBox.shrink(); 25 } 26 return Center( 27 child: FlatButton( 28 onPressed: () { 29 setState(() => number++); 30 }, 31 child: Text("$number"), 32 ), 33 ); 34 }, 35 ), 36 ); 37 } 38}

ちなみに、FutureBuilderを使わなくても以下のように書くことができ、次のような処理の流れになります。

  1. 非同期処理が開始
  2. 初回buildが呼ばれる(number == nullなので何も表示されない)
  3. 非同期処理が完了し、setStateが呼ばれる(number != nullなのでテキストとボタンが表示される)

dart

1class SetStateScreen extends StatefulWidget { 2 3 _SetStateScreenState createState() => _SetStateScreenState(); 4} 5 6class _SetStateScreenState extends State<SetStateScreen> { 7 int number; 8 9 10 void didChangeDependencies() { 11 super.didChangeDependencies(); 12 if (number == null) { 13 setInitialData(); 14 } 15 } 16 17 Future<void> setInitialData() async { 18 setState(() => number = 0); // 実際は非同期でデータを取ってきて代入する 19 } 20 21 22 Widget build(BuildContext context) { 23 return Container( 24 color: Colors.white, 25 child: number == null 26 ? const SizedBox.shrink() 27 : Center( 28 child: FlatButton( 29 onPressed: () { 30 setState(() => number++); 31 }, 32 child: Text("$number"), 33 ), 34 ), 35 ); 36 } 37}

投稿2020/08/28 05:57

nskhei

総合スコア704

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

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

matasaburo

2020/09/09 02:34

返信が遅れてしまってすいません。numberを用意して、初期化を行ったかどうかを判定するというのは良いやり方ですね!参考になりました、ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問