Flutter Widget刷新时机以及优化

在Flutter中,当widget树中的一个widget需要更新时,Flutter会根据以下三个因素来决定是否更新widget:

Widget的Type是否相同
当widget树中的一个widget需要更新时,Flutter会首先检查widget的Type是否相同。如果新的widget和旧的widget的Type不同,那么Flutter将会创建一个新的widget,并将其插入到widget树中。

例如,假设我们有一个Text widget,它的文本内容随着时间而变化:

Text(
  _getTime(),
  style: TextStyle(fontSize: 16.0),
),

String _getTime() {
  var now = DateTime.now();
  return '${now.hour}:${now.minute}:${now.second}';
}

在上述代码中,我们使用一个函数_getTime来获取当前时间,并将其作为Text widget的文本内容。每秒钟,我们会调用setState来通知Flutter更新widget的状态,从而更新文本内容。

在每次更新时,Flutter会检查新的Text widget和旧的Text widget的Type是否相同。由于它们的Type相同,Flutter将只更新它们的属性,而不会创建新的widget。这可以提高应用程序的性能,并确保widget的正确更新。

Widget的Key是否相同
当widget树中的一个widget需要更新时,Flutter会其次检查widget的Key是否相同。如果新的widget和旧的widget的Key相同,那么Flutter将会重用旧的widget,并仅更新它的属性。否则,Flutter将会创建一个新的widget,并将其插入到widget树中。

Row(
  children: [
    ElevatedButton(
      onPressed: () {},
      child: Text('Button 1'),
    ),
    ElevatedButton(
      onPressed: () {},
      child: Text('Button 2'),
    ),
  ],
)

如果我们在应用程序中多次使用这个Row,但没有为它们指定Key,则当我们更新其中一个按钮的属性时,Flutter会重新构建整个Row,这会降低性能。
相比之下,当我们为widget指定带UniqueKey的Key时,Flutter将能够区分不同的widget,并且只更新发生变化的部分。这可以提高应用程序的性能,并确保widget的正确更新。
假设我们有一个表单,包含多个文本输入框。我们希望能够检测表单中任何一个输入框的值是否发生了变化,以便在用户试图离开表单时提示用户保存更改。我们可以为每个输入框都指定一个唯一的Key,这样当用户修改任何一个输入框时,Flutter将只更新它发生了变化的输入框,而不会更新其他输入框。

class MyForm extends StatefulWidget {
  @override
  _MyFormState createState() => _MyFormState();
}

class _MyFormState extends State {
  final _formKey = GlobalKey();
  final _nameKey = UniqueKey();
  final _emailKey = UniqueKey();
  final _phoneKey = UniqueKey();

  String _name;
  String _email;
  String _phone;

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          TextFormField(
            key: _nameKey,
            initialValue: _name,
            decoration: InputDecoration(labelText: 'Name'),
            onChanged: (value) => setState(() => _name = value),
          ),
          TextFormField(
            key: _emailKey,
            initialValue: _email,
            decoration: InputDecoration(labelText: 'Email'),
            onChanged: (value) => setState(() => _email = value),
          ),
          TextFormField(
            key: _phoneKey,
            initialValue: _phone,
            decoration: InputDecoration(labelText: 'Phone'),
            onChanged: (value) => setState(() => _phone = value),
          ),
          ElevatedButton(
            onPressed: () {
              if (_formKey.currentState.validate()) {
                // 不会每次点击,输入框里面的值都消失了
                
              }
            },
            child: Text('Save'),
          ),
        ],
      ),
    );
  }
}

在上述代码中,我们为每个输入框都指定了一个唯一的Key,以确保它们能够正确地重用并仅更新它们发生变化的部分。我们还将每个输入框的值保存在相应的私有变量中,并使用setState来通知Flutter更新它们的值。

Widget的属性是否相同
当widget的Type和Key都相同时,Flutter将只更新widget的属性。以下是一个示例,演示了如何使用Key和Type来优化一个包含多个列表项的列表的性能。

假设我们有一个列表,其中包含多个列表项。我们希望能够检测列表中任何一个列表项的状态是否发生了变化,以便在需要时更新列表项的显示。我们可以为每个列表项都指定一个唯一的Key,并确保它们的Type不变,这样当列表项的状态发生变化时,Flutter将只更新发生了变化的列表项,而不会更新其他列表项。

class MyList extends StatefulWidget {
  @override
  _MyListState createState() => _MyListState();
}

class _MyListState extends State {
  final _items = List.generate(100, (index) => 'Item $index');

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: _items.length,
      itemBuilder: (context, index) {
        final item = _items[index];
        return MyListItem(
          key: ValueKey(item),
          title: item,
        );
      },
    );
  }
}

class MyListItem extends StatefulWidget {
  final String title;

  MyListItem({Key key, this.title}) : super(key: key);

  @override
  _MyListItemState createState() => _MyListItemState();
}

class _MyListItemState extends State {
  bool _isChecked = false;

  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Text(widget.title),
      leading: Checkbox(
        value: _isChecked,
        // 点击之后不会刷新整个列表
        onChanged: (value) => setState(() => _isChecked = value), 
      ),
    );
  }
}

在上述代码中,我们使用ListView.builder来构建列表,并为每个列表项都指定一个唯一的Key。当构建列表项时,我们使用MyListItem widget来包装它们,并将其title作为属性传递。在MyListItem widget中,我们使用Checkbox来表示列表项的状态,并将其值保存在私有变量_isChecked中。通过使用Key和Type,我们可以确保Flutter只更新发生了变化的列表项,并提高应用程序的性能和响应性能。

你可能感兴趣的:(Flutter,flutter,javascript,前端)