プロバイダーパッケージはInheritedWidget
を使用します。これは、ダイアログにいるときにプロバイダーにアクセスしたい場合の問題です。を使用してダイアログをロードした場合
showDialog(... builder: (context) => MyDialog);
ダイアログがメインウィジェットツリーの一部ではないため、InheritedWidget
を使用して何にもアクセスできません。これは、プロバイダープロバイダーにアクセスできないことも意味しますよね?
私の質問は、メインアプリウィジェットツリーの一部ではない場合、ダイアログでプロバイダーにアクセスするにはどうすればよいですか?
final firebaseAuth = Provider.of<FirebaseAuth>(context);
BLoCs
の使用に関しても同じ問題があります。 InheritedWidget
を使用してダイアログでそれらを取得しようとすると、失敗します。コンストラクタでBLoC
を渡すことでこれを回避しましたが、これはInheritedWidgets
の目的に反するようです。
データセットをアラートダイアログに渡すことで、プロバイダーデータにアクセスできました。興味深いことに、ダイアログの変更を確認するには、ダイアログでsetState()を呼び出す必要があります。
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
final provider = Provider.of<DataSet>(context);
return Scaffold(
body: Container(
child: RaisedButton(
child: Text('Show Dialog'),
onPressed: () {
showDialog(context: context,
builder: (context) {
return DialogContent(dataSet: provider);
});
},
),
),
);
}
}
class DialogContent extends StatefulWidget {
final DataSet dataSet;
const DialogContent({Key key, this.dataSet}) : super(key: key);
@override
_DialogContentState createState() => _DialogContentState();
}
class _DialogContentState extends State<DialogContent> {
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Dialog with data'),
content: Text('${widget.dataSet.pieceOfData}'),
actions: <Widget>[
FlatButton(
child: Text('Increase Data'),
onPressed: () {
setState(() {
widget.dataSet.increaseData();
});
},
),
],
);
}
}
class DataSet with ChangeNotifier {
int pieceOfData = 1;
increaseData() {
pieceOfData += 1;
notifyListeners();
}
}
ダイアログの新しいコンテキストでアクセスするには、提供されているものを直接ダイアログコンストラクターに渡す必要があります。また、ダイアログに非常に深いウィジェットツリーがあり、より深いところからアクセスしたい場合は、ダイアログツリーの上部にある新しいプロバイダーウィジェットにそれを与えることもできます。
Blocを使用している場合は、通常、プロバイダーウィジェットが破棄されてストリームコントローラー/サブスクリプションをクリーンアップするときに、Blocのdisposeメソッドを呼び出すようにプロバイダーに指示します。明らかに、ブロックをダイアログに再提供している場合、またはこのブロックがダイアログの外部で使用されている場合は、これを実行したくない場合があります。
ダイアログでステートフルまたはステートレスウィジェットを使用するかどうかは、ブロックにアクセスできる限り、streambuilderを使用して、通常どおりストリームを聞くことができます。
例:
class EditEventDialog extends StatelessWidget {
final GroupBloc groupBloc;
EditEventDialog({this.groupBloc})
: assert(groupBloc != null);
@override
Widget build(BuildContext context) {
return Provider(
builder: (context) => groupBloc,
child: Dialog(
child: Container(
height: 400.0,
width: 200.0,
child: StreamBuilder<StatusStreamType>(
stream: groupBloc.statusStream,
builder: (context, snapshot) {
....
それを呼び出すには:
onPressed: () => showDialog(
builder: (newContext) {
GroupBloc groupBloc = Provider.of<GroupBloc>(context);
return EditEventDialog(
groupBloc: groupBloc,
);
},
context: context,
)