简体   繁体   English

颤振:父级重建后未重建子小部件

[英]flutter: child widget not rebuilt after parent rebuild

Version:版本:
Flutter-Version: 1.12.14 channel dev Flutter 版本:1.12.14 通道开发
Dart-Version: 2.7.0 Dart 版本:2.7.0

Question:题:
I wan write a Todo App.我想写一个 Todo 应用程序。 when i click floatbutton add a new Todo, but in some cases its not work well.当我点击浮动按钮添加一个新的 Todo 时,但在某些情况下它不能很好地工作。

The problem in Scaffold.body , detials in code. Scaffold.body的问题,代码中的细节。

it work well when i use TodoPage(todoList: _todoList) .当我使用TodoPage(todoList: _todoList)时它运行良好。

_pageList.elementAt(_activeIndex) is not work when i submit textfield .当我提交 textfield 时_pageList.elementAt(_activeIndex)不起作用。

I found the print('Build Home') print after submit but print('Build TodoPage') not print.我发现提交后print('Build Home')打印但print('Build TodoPage')不打印。

why???为什么???

My Code:我的代码:

import 'package:flutter/material.dart';

void main() => runApp(App());

class App extends StatelessWidget{
  @override
  Widget build(BuildContext context){
    return MaterialApp(
      title: 'TodoList',
      home: Home(),
    );
  }
}


class Home extends StatefulWidget{
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home>{
  List<String> _todoList = ['a', 'b', 'c'];
  TextEditingController _controller;
  List<Widget> _pageList;
  int _activeIndex;
  Widget _curPage;

  @override
  void initState(){
    super.initState();
    _activeIndex = 0;
    _pageList = [TodoPage(todoList: _todoList,), OtherPage()];
    _curPage = _pageList[_activeIndex];
    _controller = TextEditingController();
  }

  @override
  Widget build(BuildContext context){
    print('build Home');
    return Scaffold(
      appBar: AppBar(title: Text('Todo'),),
      body: _pageList.elementAt(_activeIndex), // this is not work
      // body: TodoPage(todoList: _todoList,), // this is work well
      floatingActionButton: FloatingActionButton(
        onPressed: _openDlg,
        child: Icon(Icons.add),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(icon: Icon(Icons.list), title: Text('Todo')),
          BottomNavigationBarItem(icon: Icon(Icons.favorite), title: Text('Other')),
        ],
        currentIndex: _activeIndex,
        selectedItemColor: Colors.blue,
        onTap: _onMenuTap,
      ),
    );
  }


  _onMenuTap(int index){
    setState(() {
      _activeIndex = index;
    });
  }

  _openDlg(){
    showDialog(
      context: context,
      builder: (BuildContext context){
        return SimpleDialog(
          children: <Widget>[
            TextField(
              controller: _controller,
            ),
            SimpleDialogOption(
              child: FloatingActionButton(child: Text('submit'), onPressed: _addTodo,),
            )
          ],
        );
      }
    );
  }

  _addTodo(){
    print(_controller.text);
    setState(() {
      _todoList.add(_controller.text);
    });
  }
}

class TodoPage extends StatefulWidget{
  TodoPage({Key key, this.todoList}): super(key: key);
  List<String> todoList;
  _TodoPageState createState() => _TodoPageState();
}

class _TodoPageState extends State<TodoPage>{

  @override
  void initState(){
    super.initState();
  }

  @override 
  Widget build(BuildContext context){
    print('build TodoPage');
    return Column(
      children: _buildTodoList(),
    );
  }

  List <Widget> _buildTodoList(){
    return widget.todoList.map((todo){
      return Text(todo, style: TextStyle(fontSize: 30),);
    }).toList();
  }
}


class OtherPage extends StatelessWidget{
  @override
  Widget build(BuildContext context){
    return Center(child: Text('Other Page'));
  }
}


That is logical.这是合乎逻辑的。

You are reusing an existing instance of a Widget , and widgets are immutable.您正在重用Widget的现有实例,并且小部件是不可变的。 As such, the framework notice that the instance of the widget did not change and doesn't call build to optimize performances.因此,框架注意到小部件的实例没有改变,并且不会调用build来优化性能。

Your problem being, you violated the rule of widgets being immutable, which makes this optimization break your app.你的问题是,你违反了小部件不可变的规则,这使得这个优化破坏了你的应用程序。

What you did:你做了什么:

class MyState extends State<MyStatefulWidget> {
  SomeWidget myWidget = SomeWidget()..someProperty = "initial value";

  void onSomething() {
    setState(() {
      myWidget.someProperty = "new value";
    });
  }

  @override
  Widget build(BuildContext context) {
    return myWidget;
  }
}

What you should instead do:你应该做什么:

class MyState extends State<MyStatefulWidget> {
  SomeWidget myWidget = SomeWidget(someProperty: "initial value");

  void onSomething() {
    setState(() {
      myWidget = SomeWidget(someProperty: "new value");
    });
  }

  @override
  Widget build(BuildContext context) {
    return myWidget;
  }
}

Alternatively, just don't cache the widget instance at all.或者,根本不缓存小部件实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Flutter 重建父部件 - Flutter rebuild parent widget 更改父部件高度而不导致子部件重建 Flutter - Change the parent widget height without causing the child to rebuild Flutter 如何在不重建父小部件的情况下将数据子小部件传递给子小部件? - How to pass data child to child widget without rebuild parent widget in flutter? 每次重建子小部件时调用父小部件的 function - call a function of a parent widget each time when a child widget is rebuilt 子控件更改时更改父变量并重建父控件 Flutter - Change parent variable and rebuild parent widget when child widget changes Flutter Flutter - 为什么每次重建父小部件时都不会调用子小部件的 initState()? - Flutter - Why is child widget's initState() is not called on every rebuild of Parent widget? Flutter Provider 在父级消费者之前重建小部件 - Flutter Provider rebuilt widget before parent's Consumer 在 flutter 中渲染时间后将子 Widget 的大小获取到父 Widget - Getting Size of a child Widget to a Parent Widget after rendering time in flutter 在颤动中强制重建有状态的子小部件 - Force rebuild of a stateful child widget in flutter Flutter 更改其中一项属性后的小部件重建 - Flutter Widget rebuild after one of the property changed
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM