web-dev-qa-db-ja.com

Flutterの状態の更新

私はFlutterを初めて使用し、状態がどのように機能するかを理解するのに問題があります。
アプリでStatefulWidgetとしてページを設定し、そのページの状態内で、主要コンポーネントの1つが個別のStatefulWidgetです。

内側のウィジェットは質問を表示し、ユーザーが回答を入力できるようにします。

それから私がやりたかったのは、同じページに次の答えを表示することでした。

回答が入力されると、内部ウィジェットがページの状態にコールバックします。

内部ウィジェットを別のコピーに置き換えようとしましたが、状態がリセットされません。つまり、新しい状態は作成されず、initState()が再度呼び出されることはありません。

これを実現するために使用する必要がある特定の呼び出しまたはメソッドはありますか?

編集:たとえば、次のような場合

_import 'package:flutter/material.Dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  void initState(){
     changeContent();
  }

  Widget innerWidget;
  void changeContent(){
     setState((){
        innerWidget = new CustomStatefullWidget();
     }
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            innerWidget
          ],
        ),
      ),
    );
  }
}
_

ここで、CustomStatefullWidgetは、ページのスタンドアロンのインタラクティブな部分として作成したクラスです。この例では、実際のコンテンツは重要ではありません。

私が予想していたのは、changeContent()が呼び出されると、innerWidgetが新しい状態になるということでしたが、そうではありません。その状態はすでにツリーに保存されており、ウィジェットの新しいインスタンスが作成されても更新されません。
フラッターにツリーのその部分をクリアさせたり、状態をリセットしたいことを認識させたりするにはどうすればよいですか?

これが予想される動作です。親がフラッターを再構築するとき、新しいウィジェットツリーを古いウィジェットツリーと比較します。

このようにして、フラッターはどのウィジェットが「更新」され、どのウィジェットが追加/削除されたかを知ることができます。

追加されたウィジェットの場合、新しい状態が作成されます。 initStateが呼び出されます。更新されたウィジェットの場合; flutterは古いウィジェットを再利用し、古い「ウィジェット」部分をパラメーターとして渡すことでdidUpdateWidgetを呼び出します。削除されたウィジェットについては、disposeを呼び出します。

あなたの場合、initStateがもう一度呼び出されることを期待していました。しかし実際には「更新」されました。


この時点から、状態をリセットするための2つの解決策があります。

didUpdateWidgetを実装します。それはあなたの状態をリセットするか、あなたが望む他のことをするでしょう。これが最適なアプローチであり、検討する必要があります。 「新しいstatefulwidget」の子を必ずしもリセットしたくないので。

「これは別のウィジェットです。古いウィジェットを再利用しないでください」とフラッターに伝える「怠惰な」ソリューションもあります。これは、Keyを使用して実現されます。

キーの使用法の詳細 ここ

これは、changeContentメソッドを次のように変更するのと同じくらい簡単です。

Widget innerWidget;
void changeContent(){
  setState((){
      innerWidget = new CustomStatefullWidget(key: new UniqueKey());
  }
}
11
Rémi Rousselet