Flutter State 深入理解

天涯不歸客發表於1970-01-01

本文主要介紹 Flutter 應用程式中 WidgetStateContextInheritedWidget 等重要概念。 尤其注意的是 InheritedWidget,它是最重要且介紹較少的 Widget 之一。


前言

每個 Flutter 開發人員都需要完全理解 WidgetStateContext 概念。

雖然,有很多文件可以查詢,但想要清晰地解釋這些概念,還是有一定難度。

本文會對這些概念進行剖析,力圖使你能夠進一步瞭解這些概念:

  • 有狀態和無狀態 Widegt 的區別
  • Context 是什麼
  • State 是什麼以及如何使用它
  • Context 與其 State 物件之間的關係
  • InheritedWidget 以及在 Widgets 樹中傳遞資訊的方式
  • rebuild 概念

第一部分:概念

Widget

Flutter 中,一切都是 Widget

Widget 視為視覺化元件(或視覺化互動的元件)。

當您需要構建直接或間接佈局關係時,您正在使用 Widget

Widget 樹

Widget 是以樹結構組織起來的。

包含其他 WidgetWidget 稱為父 Widget(或 Widget 容器)。包含在父 Widget 中的 Widget 稱為子 Widget

Flutter 自動生成的應用程式來進行說明。 構建程式碼:

@overrideWidget build(BuildContext){ 
return new Scaffold( appBar: new AppBar( title: new Text(widget.title), ), body: new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children: <
Widget>
[ new Text( 'You have pushed the button this many times:', ), new Text( '$_counter', style: Theme.of(context).textTheme.display1, ), ], ), ), floatingActionButton: new FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: new Icon(Icons.add), ), );

}複製程式碼

我們將獲得以下 Widget 樹(僅限程式碼中存在的 Widget 列表):

Flutter State 深入理解

Context 上下文

另一個重要的概念是 Context

Context 是構建所有 Widgets 樹結構中的 Widget 的位置引用。

簡而言之,將 Context 視為 Widgets 樹的一部分。

一個 Context 僅屬於一個 Widget。同樣具有父子關係,如果 Widget A 具有子 Widgets,則 Widget AContext 將成為子 WidgetContext 的父 Context

很明顯,Context 是關聯在一起,組成一個 Context 樹(父子關係)。

現在,我們使用上圖說明 Context 的概念,每種顏色代表一個 Context(除了 MyApp,它是不同的):

Flutter State 深入理解

Context 可見性:某些屬性只能在其自己的 Context 中或在其父 Context 中可見。

使用這種語法,我們可以從子 Context 追根溯源,很容易找到一個祖先(或者父)Widget

舉例,考慮 Scaffold >
Center >
Column >
Text:context.ancestorWidgetOfExactType(Scaffold)=>
通過從 Text Context 向上查詢到頂部 Scaffold

從父 Context 中,也可以找到後代(=子) Widget,但不建議這樣做(我們稍後會討論)。

兩種 Widgets

無狀態 StatelessWidget

這些可視元件,只依賴它們自己的配置資訊,並不依賴於任何外部資訊。這些配置資訊在構建時由其父元件提供。

換句話說,這些 Widgets 一旦建立就不關心任何變化。

這些 Widgets 被稱為無狀態 Widgets

這些 Widgets 的典型示例是 Text,Row,Column,Container ...... 在構建時,我們只是將一些引數傳遞給它們。

引數可以是文字,尺寸甚至其他 Widgets。 唯一重要的是這個配置資訊一旦應用,在下一個構建過程之前不會改變。

無狀態 Widget 只能在載入或者構建 Widget 時繪製一次,這意味著無法基於任何事件或使用者操作重繪該 Widget

StatelessWidget 生命週期

無狀態 Widget 相關的程式碼的典型結構如下。

如您所見,我們可以將一些額外的引數傳遞給它的建構函式。 但是,請記住,這些引數不會在以後階段發生變化,只能按原樣使用。

class MyAppStatelessWidget extends StatelessWidget { 
MyAppStatelessWidget({
Key key, this.parameter,
}): super(key:key);
final parameter;
@override Widget build(BuildContext context){
return new ...
}
}複製程式碼

StatelessWidget 的另一個方法 createElement 也可以被複寫,但你幾乎不會這樣做。 唯一需要被複寫的是 · build 函式。

這種無狀態 Widget 的生命週期很簡單:

  • 初始化
  • 通過 build 進行渲染

有狀態 StatefulWidget

某些 Widge 需要處理一些在 Widget 生命週期內會發生變化的內部資料。

這些 Widget 儲存的資料集在 Widget 的生命週期中可能會有所不同,這樣的資料集被稱為為 State

這樣的 Widget 被稱為有狀態 Widget

此類 Widget 的示例可以是核取方塊列表,也可以是根據條件禁用的 Button

State

State 定義 StatefulWidget 例項的 行為 部分。

它包含 Widget 互動 的資訊:

  • 行為
  • 佈局

施加於 State 的任何更改都會強制 Widget 重建。

State 與 Context 之間的關係

對於有狀態 WidgetsStateContext 相關聯。 此關聯是永久性的,State 物件永遠不會更改其 Context

即使可以在 Widgets 樹內移動 Widget ContextState 仍將與該 Context 相關聯。

StateContext 關聯時,State 被視為已掛載。

至關重要:

由於State 物件與 Context 相關聯,這意味著 State 物件不能(直接)通過另一個 Context 訪問! (我們將在稍後討論這個問題)。

有狀態 Widget 生命週期

基本概念已經介紹過了,是時候深入瞭解了。

由於本文的主要意圖是用 “變數” 資料來解釋 State 的概念,因此會故意跳過某些與 Stateful Widget 可複寫方法相關的任何解釋,這些方法與此沒有特別的關係。 這些可複寫的方法是 didUpdateWidgetdeactivatereassemble

class MyStatefulWidget extends StatefulWidget { 
MyStatefulWidget({Key key, this.title
}) : super(key: key);
final String title;
@override _MyStatefulWidgetState createState() =>
_MyStatefulWidgetState();

}class _MyStatefulWidgetState extends State<
MyStatefulWidget>
{
@override void initState() {
// TODO: implement initState super.initState();

} @override void didChangeDependencies() {
// TODO: implement didChangeDependencies super.didChangeDependencies();

} @override void dispose() {
// TODO: implement dispose super.dispose();

} @override Widget build(BuildContext context) {
return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <
Widget>
[ Text( 'You have pushed the button this many times:', ), Text( '', style: Theme.of(context).textTheme.display1, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: (){
}, tooltip: 'Increment', child: Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. );

}
}複製程式碼

下面時序圖顯示了建立有狀態 Widget 相關的操作。 在圖的右側,標註了 State 物件的內部狀態。 同時您可以看 ContextState 關聯的時刻,從而變為有效的(掛載)。

Flutter State 深入理解

initState()

initState() 方法是在建立 State 物件後要呼叫的第一個方法(在建構函式之後)。需要執行自定義初始化內容時,需要複寫此方法。 通常初始化,動畫,邏輯控制等。如果重寫此方法,需要先呼叫 super.initState() 方法。

在這個方法中,Context 可用但你還不能真正使用它,因為框架還沒有完全將 State 與它相關聯。

一旦 initState() 方法執行完成,State 物件完成初始化並且 Context 可用。

State 物件的生命週期內,不會再呼叫 initState() 方法。即 initState() 只被呼叫一次。

didChangeDependencies()

didChangeDependencies() 方法是要呼叫的第二個方法。

在此階段,由於 Context 可用,您可以使用它。

如果您的 Widget 連結到 InheritedWidget,並且需要初始化某些偵聽器(基於 Context),則需要複寫此方法。

請注意,如果您的 Widget 關聯到 InheritedWidget,則每次重建此 Widget 時都會呼叫此方法。

如果重寫此方法,則應首先呼叫 super.didChangeDependencies()

build()

build(BuildContext context) 方法在 didChangeDependencies()(和didUpdateWidget)之後呼叫。

這是您構建 Widgets(可能還有任何子樹)的地方。

每次 State 物件更改時(或者當 InheritedWidget 需要通知 “已註冊” 的 Widget 時)都會呼叫此方法!

如果要主動重建,您可以呼叫 setState ( () {...
})
方法。

dispose()

Widget 廢棄時呼叫 dispose() 方法。

如果需要執行一些清理(例如偵聽器)工作,需要複寫此方法,之後呼叫 super.dispose()

有狀態和無狀態 Widget 如何選擇

Widget無狀態或有狀態?如何選擇。

為了回答這個問題,請問問自己:

在我的 Widget 生命週期中,是否需要考慮一個變數, 將要更改,何時更改,從而強制重建 Widget

如果問題的答案是肯定的,那麼您需要一個有狀態 Widget,否則,您需要一個無狀態 Widget

舉例:

  • 用於顯示覆選框列表的 Widget。要顯示覆選框,您需要考慮一系列 item。每個 item 都是一個具有 title 和 ‘status’ 的物件。如果單擊核取方塊,則會切換相應的 item.status

    在這種情況下,您需要使用有狀態 Widget 來記住專案的狀態,以便能夠重繪核取方塊。

  • 單一表格, 該表格 Widget 允許使用者輸入,並將輸入之後的表格傳送到伺服器。

    在這種情況下,除非您需要在提交表單之前驗證表單或執行任何其他操作,否則無狀態 Widget 可能就足夠了。

有狀態 Widget 由兩部分組成

Widget 定義

class MyStatefulWidget extends StatefulWidget { 
MyStatefulWidget({Key key, this.title
}) : super(key: key);
final String title;
@override _MyStatefulWidgetState createState() =>
_MyStatefulWidgetState();

}複製程式碼

第一部分 MyStatefulWidget 通常是 Widget 的公共部分。 當您要將其新增到 Widget 樹,可以例項化此Widget。此部分在 Widget 的生命週期內不會發生變化,但可以接受其相應的 State 例項引數。

請注意,在 Widget 的第一部分定義的任何變數通常在其生命週期內不會更改。

State 定義

class _MyStatefulWidgetState extends State<
MyStatefulWidget>
{
... @override Widget build(BuildContext context){
...
}
}複製程式碼

第二部分 _MyStatefulWidgetState 是在 Widget 的生命週期中變化的部分,並在每次應用修改時強制重建 Widget例項。 名稱開頭的 _ 字元表示該類對當前 .dart 檔案是私有的。

如果需要在 .dart 檔案之外引用此類,去掉 _ 字首即可。

_MyStatefulWidgetState 類可以使用 widget.{變數名
}
訪問儲存在 MyStatefulWidget 中的任何變數。 示例:widget.color

Widget 的唯一標識 – Key

在Flutter中,每個Widget都是唯一標識的。這個唯一標識由框架在構建/渲染時定義。

此唯一標識對應為可選的 Key 引數。 如果省略,Flutter將為您生成一個。

在某些情況下,您可能需要使用此 Key,以便可以通過 Key 訪問 Widget

為此,您可以使用以下類之一:GlobalKeyLocalKeyUniqueKeyObjectKey

GlobalKey確保 Key 在整個應用程式中是唯一的。

使用 Widget 的唯一標識 Key

GlobalKey myKey = new GlobalKey();
... @override Widget build(BuildContext context){
return new MyWidget( key: myKey );

}複製程式碼

第二部分, 如何訪問 State

如前所述,State 關聯一個 ContextContext 關聯一個 Widget 例項。

1. Widget 本身

從理論上講,唯一能夠訪問狀態的是 Widget State 本身。

在這種情況下,沒有困難。 Widget State 類訪問其任何內部變數。

2. 子 Widget

有時候,父 Widget 可能需要根據其子 Widget 的狀態執行特定任務。

在Flutter中,每個Widget都有一個唯一的標識,由框架在構建/渲染時確定。

如前所示,您可以使用 key 引數強制標識 Widget,

 ...    GlobalKey<
MyStatefulWidgetState>
myWidgetStateKey = new GlobalKey<
MyStatefulWidgetState>
();
... @override Widget build(BuildContext context){
return new MyStatefulWidget( key: myWidgetStateKey, color: Colors.blue, );

}複製程式碼

一旦確定,父 Widget 可以通過以下方式訪問其子 Widget 的狀態:

myWidgetStateKey.currentState

讓我們考慮一個基本示例,當使用者點選按鈕時顯示 SnackBar。 由於 SnackBarScaffold的子 Widget,它不能直接訪問 Scaffold 的任何其他子 Widget。 因此,訪問它的唯一方法是 ScaffoldState,公開一個公共方法來顯示 SnackBar

class _MyScreenState extends State<
MyScreen>
{
/// the unique identity of the Scaffold final GlobalKey<
ScaffoldState>
_scaffoldKey = new GlobalKey<
ScaffoldState>
();
@override Widget build(BuildContext context){
return new Scaffold( key: _scaffoldKey, appBar: new AppBar( title: new Text('My Screen'), ), body: new Center( new RaiseButton( child: new Text('Hit me'), onPressed: (){
_scaffoldKey.currentState.showSnackBar( new SnackBar( content: new Text('This is the Snackbar...'), ) );

} ), ), );

}
}複製程式碼

3. Widget 祖先

Flutter State 深入理解

1. 帶狀態的 Widget(紅色)需要暴露其狀態

為了公開它的狀態,Widget需要在建立時記錄它,如下所示:

class MyExposingWidget extends StatefulWidget { 
MyExposingWidgetState myState;
@override MyExposingWidgetState createState(){
myState = new MyExposingWidgetState();
return myState;

}
}複製程式碼

2. Widget State 需要暴露 getters/setters

為了讓其他 Widget可以 設定/獲取 State屬性,Widget State 需要通過以下方式授權訪問:

  • public 屬性 (不推薦)
  • getter / setter

例子:

class MyExposingWidgetState extends State<
MyExposingWidget>
{
Color _color;
Color get color =>
_color;
...
}複製程式碼

3. 藍色 Widget 獲得 State 引用

class MyChildWidget extends StatelessWidget { 
@override Widget build(BuildContext context){
final MyExposingWidget widget = context.ancestorWidgetOfExactType(MyExposingWidget);
final MyExposingWidgetState state = widget?.myState;
return new Container( color: state == null ? Colors.blue : state.color, );

}
}複製程式碼

這個解決方案很容易實現,但子 Widget 無法知道它何時需要重建,

它必須等待重建才能重新整理其內容,這將導致UI無法及時重新整理。

下一節將討論 Inherited Widget 概念,它可以解決這個問題。

InheritedWidget

簡而言之,InheritedWidget 允許在 Widget 樹中有效地傳遞(和共享)資訊。

InheritedWidget 是一個特殊的 Widget,您可以將其插入 Widget 樹中,作為一個 Widget 子樹的父節點。 該子樹的所有 Widget 都能夠訪問 InheritedWidget 公開的資料。

基礎知識

為了解釋 InheritedWidget,讓我們考慮以下程式碼:

class MyInheritedWidget extends InheritedWidget { 
MyInheritedWidget({
Key key, @required Widget child, this.data,
}): super(key: key, child: child);
final data;
static MyInheritedWidget of(BuildContext context) {
return context.inheritFromWidgetOfExactType(MyInheritedWidget);

} @override bool updateShouldNotify(MyInheritedWidget oldWidget) =>
data != oldWidget.data;

}複製程式碼

此程式碼定義了一個名為 MyInheritedWidget 的 Widget,目的是 “共享” 所有 Widget 中的某些資料。

如前所述,為了能夠傳遞/共享某些資料,需要將 InheritedWidget 定位在 Widget 樹的頂部,這解釋為什麼 InheritedWidget 建構函式設定 Widget@required

靜態方法 MyInheritedWidget(BuildContext context) 允許所有子 Widget 獲取最近包含 ContextMyInheritedWidget 例項(參見後面的內容)。

最後重寫 updateShouldNotify 方法,用於設定 InheritedWidget 是否必須通知所有子 Widget(已註冊/已訂閱),如果資料發生修改(請參閱下文)。

因此,我們需要將它放在樹節點上,如下所示:

class MyParentWidget... { 
... @override Widget build(BuildContext context){
return new MyInheritedWidget( data: counter, child: new Row( children: <
Widget>
[ ... ], ), );

}
}複製程式碼

Widget 如何訪問 InheritedWidget 的資料

在構建子 Widget 時,將獲得 InheritedWidget 的引用,如下所示:

class MyChildWidget... { 
... @override Widget build(BuildContext context){
final MyInheritedWidget inheritedWidget = MyInheritedWidget.of(context);
/// /// From this moment, the widget can use the data, exposed by the MyInheritedWidget /// by calling: inheritedWidget.data /// return new Container( color: inheritedWidget.data.color, );

}
}複製程式碼

如何在 Widget 之間進行互動 ?

思考下面 Widget 樹。

Flutter State 深入理解

為了說明一種互動方式,我們假設如下:

  • Widget A 是一個按鈕,點選時將貨物新增到購物車;
  • Widget B 是一個文字,顯示購物車中商品數量;
  • Widget C 位於 Widget B 旁邊,是一個文字;
  • 我們希望在按下 Widget A 時自動在 Widget B 購物車中顯示正確數量的專案,但我們不希望重建 Widget CInheritedWidget 應用場景正式於此!

示例程式碼 github

main.dart:

import 'package:flutter/material.dart';
import 'package:flutter_app_demo/inherited.dart';
import 'package:flutter_app_demo/widgetA.dart';
import 'package:flutter_app_demo/widgetB.dart';
import 'package:flutter_app_demo/widgetC.dart';
void main() =>
runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application. @override Widget build(BuildContext context) {
return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyStatefulWidget(title: 'Flutter Demo Home Page'), );

}
}class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key, this.title
}) : super(key: key);
final String title;
@override _MyStatefulWidgetState createState() =>
_MyStatefulWidgetState();

}class _MyStatefulWidgetState extends State<
MyStatefulWidget>
{
@override Widget build(BuildContext context) {
return MyInheritedWidget( child: Scaffold( appBar: AppBar( title: Text('I am Tree'), ), body: Column( children: <
Widget>
[ WidgetA(), Padding(padding: EdgeInsets.all(15.0),), Container( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <
Widget>
[ WidgetB(), WidgetC(), ], ), ) ], ), ), );

}
}複製程式碼

inherited.dart

import 'package:flutter/material.dart';
class MyInheritedWidget extends StatefulWidget{
MyInheritedWidget({Key key, this.child,
}):super(key: key);
final Widget child;
MyInheritedWidgetState createState() =>
new MyInheritedWidgetState();
static MyInheritedWidgetState of(BuildContext context){
return (context.inheritFromWidgetOfExactType(_MyInherited) as _MyInherited).data;

}
}class MyInheritedWidgetState extends State<
MyInheritedWidget>
{
List<
Item>
_items = <
Item>
[];
int get itemsCount =>
_items.length;
void addItem(String name){
setState(() {
_items.add(new Item(name));

});

} @override Widget build(BuildContext context) {
return new _MyInherited(child: widget.child, data: this);

}
}class _MyInherited extends InheritedWidget {
_MyInherited({
Key key, @required Widget child, @required this.data,
}) : super(key: key, child: child);
final MyInheritedWidgetState data;
@override bool updateShouldNotify(_MyInherited oldWidget) {
return true;

}
}class Item{
String name;
Item(this.name);

}複製程式碼

Widgets:

class WidgetA extends StatelessWidget { 
@override Widget build(BuildContext context) {
final MyInheritedWidgetState state = MyInheritedWidget.of(context);
return new Container( child: new RaisedButton( child: new Text('WidgetA Add Item', textAlign: TextAlign.right, overflow: TextOverflow.ellipsis, style: TextStyle( color: Colors.blue, ), ), onPressed: () {
state.addItem('new item');

}, ), );

}
}class WidgetB extends StatelessWidget{
@override Widget build(BuildContext context) {
final MyInheritedWidgetState state = MyInheritedWidget.of(context);
return new Container( child: Row( children: <
Widget>
[ Icon(Icons.shopping_cart), Text('${state.itemsCount
}'
, textAlign: TextAlign.right, overflow: TextOverflow.ellipsis, style: TextStyle( color: Colors.red, ), ), ], ), );

}
}class WidgetC extends StatelessWidget{
@override Widget build(BuildContext context) {
return new Text( 'Widget C', textAlign: TextAlign.right, overflow: TextOverflow.ellipsis, style: TextStyle(// fontWeight: FontWeight.bold, color: Colors.green[200], ), );

}
}複製程式碼

解釋說明

在這個非常基本的例子中,

  • _MyInherited 是一個 InheritedWidget,每次我們點選 Widget A 按鈕新增一個 Item 時都會被重新建立。
  • MyInheritedWidget 是一個 Widget,其狀態包含 Items 列表。 可以通過MyInheritedWidgetState of(BuildContext context)靜態方法訪問此狀態。
  • MyInheritedWidgetState 公開一個 getter(itemsCount)和一個 addItem 方法,以便它們可以被 Widget 使用。
  • 每次我們將一個 Item 新增到 StateMyInheritedWidgetState 都會重建。
  • MyStatefulWidget 類只是構建一個 Widget 樹,將 MyInheritedWidget 作為樹的根節點。
  • WidgetA 是一個簡單的 RaisedButton,當按下它時,呼叫 MyInheritedWidgetaddItem 方法。
  • WidgetB 是一個簡單的文字,顯示 MyInheritedWidgetitem數。

這一切是如何運作 ?

註冊 Widget 以供以後通知

當子 Widget 呼叫 MyInheritedWidget.of(context)時,它呼叫 MyInheritedWidget 的以下方法,將 ‘Context’ 作為引數進行傳遞。

static MyInheritedWidgetState of(BuildContext context) { 
return (context.inheritFromWidgetOfExactType(_MyInherited) as _MyInherited).data;

}複製程式碼

在內部,除了簡單地返回 MyInheritedWidgetState 的例項之外,它還向 Widget 訂閱更改通知。

在場景後面,對這個靜態方法的簡單呼叫實際上做了兩件事:

  • Widget 被自動新增到訂閱列表中,當對 _MyInherited 進行修改時, 將自動重建。
  • MyInheritedWidgetState 中引用的資料將返回給使用者。

由於 Widget AWidget B 都已使用 InheritedWidget 訂閱,因此如果對 _MyInherited 進行修改,即當單擊 Widget ARaisedButton 時,大致操作流程如下:

  1. 呼叫 MyInheritedWidgetStateaddItem 方法。
  2. MyInheritedWidgetState.addItem 方法將新項新增到 List
  3. 呼叫 setState() 重建 MyInheritedWidget
  4. 使用List的新內容建立 _MyInherited 的新例項。
  5. _MyInherited 記錄新 State
  6. 作為 InheritedWidget,它檢查是否需要通知訂閱者(答案是需要)。
  7. 它遍歷整個訂閱者列表(這裡是 Widget AWidget B )並要求他們重建。
  8. 由於 Wiget C 不是訂閱者,因此不會重建。

Widget AWidget B 都重建了,而重建 Wiget A 卻沒用,因為它沒有任何改變。如何防止這種情況發生?

訪問 InheritedWidget 時阻止某些 Widget 重建

Widget A 也被重建的原因是訪問 MyInheritedWidgetState 的方式。

如前所述,呼叫 context.inheritFromWidgetOfExactType() 方法會自動將 Widget 訂閱到訂閱列表中。

防止此自動訂閱同時仍允許 Widget A 訪問 MyInheritedWidgetState 的解決方案是更改MyInheritedWidget 的靜態方法,如下所示:

static MyInheritedWidgetState of([BuildContext context, bool rebuild = true]){ 
return (rebuild ? context.inheritFromWidgetOfExactType(_MyInherited) as _MyInherited : context.ancestorWidgetOfExactType(_MyInherited) as _MyInherited).data;

}複製程式碼

新增額外布林引數:

  • 如果 rebuild 引數為 true(預設情況下),Widget將被新增到訂閱者列表中。
  • 如果 rebuild 引數為 false,我們仍然可以訪問資料,但不使用 InheritedWidget 的內部實現。

因此,要完成解決方案,我們還需要稍微更新 Widget A 的程式碼,如下所示(我們新增 false 引數):

class WidgetA extends StatelessWidget { 
@override Widget build(BuildContext context) {
final MyInheritedWidgetState state = MyInheritedWidget.of(context, false);
return new Container( child: new RaisedButton( child: new Text('Add Item'), onPressed: () {
state.addItem('new item');

}, ), );

}
}複製程式碼

現在,按下 button 不會重建 Widget A.

總結

通篇,我們介紹了 Flutter 的核心概念, Widget, State, Context, InheritedWidget。

並且,完成了 State 之間互動的介紹。並使用 InheritedWidget 進行了 Demo製作。希望這篇文章,能夠幫助您,深入瞭解 Flutter

參考

來源:https://juejin.im/post/5c4bdee7518825254e4d4aef

相關文章