带有 return 错误的 Flutter 回调 setState() 或在构建期间调用了 markNeedsBuild

Flutter Callback with return error setState() or markNeedsBuild called during build

我使用 PopupMenuButton 来编辑 listView。对于每个尝试执行回调的 PopupMenuButton 操作(删除项目、添加项目、编辑 listView 中的项目)。比如最简单的情况就是delete

//_editorChannels - data with which I fill in the list
delete(dynamic val) {
 setState(() => _editorChannels.removeWhere((data) => data == val));
}

但是由于我将回调函数 delete 传递给小部件,因此在创建它时出现错误 setState() 或在构建过程中调用了 markNeedsBuild。如果更改并删除setState(),则不会发生错误,但是当通过回调删除项目时,列表当然不会更新。

delete(dynamic val) {
  _editorChannels.removeWhere((data) => data == val);
}

我的 PopupMenuButton 小部件

  class PopMenuWidget2 extends StatelessWidget {
  final VoidCallback onDelete;

  const PopMenuWidget2({Key key, this.onDelete}) : super(key: key);

  @override
  Widget build(BuildContext context) => PopupMenuButton<int>(
    onSelected: (result) {
      //On View
      if (result == 0) {}
      //On Edit
      if (result == 1) { }

      //OnDelete Callback run
      if (result == 2) {
        onDelete();
      }
    },
    itemBuilder: (context) => [
      PopupMenuItem(
        value: 0,
        child: Row(
          children: <Widget>[
            Icon(
              Icons.remove_red_eye_rounded,
              color: Colors.black38,
            ),
            Text('  View Option', style: TextStyle(color: Colors.black38)),
          ],
        ),
      ),
      PopupMenuItem(
        value: 1,
        child: Row(
          children: <Widget>[
            Icon(
              Icons.create,
              color: Colors.black38,
            ),
            Text('  Edit Option', style: TextStyle(color: Colors.black38)),
          ],
        ),
      ),
      PopupMenuItem(
        value: 2,
        child: Row(
          children: <Widget>[
            Icon(
              Icons.delete,
              color: Colors.black38,
            ),
            Text('  Delete Option',
                style: TextStyle(color: Colors.black38)),
          ],
        ),
      ),
    ],
  );
 }

主要小部件

  class EditorPage extends StatefulWidget {

  EditorPage({Key key, this.Channels}) : super(key: key);

  final List<Channel> Channels;

  static const String routeName = "/EditorPage";

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

  class _EditorPageState extends State<EditorPage> {
  Stream<Mock> _result;
  final _coreObj = new Core();

 List<Channel> _editorChannels;


  //callback onDelete
  delete(dynamic val) {
  setState(() => _editorChannels.removeWhere((data) => data == val));
 }

 @override
 void initState() {
 _editorChannels = widget.Channels;
 super.initState();
 }


@override
Widget build(BuildContext context) {
return DefaultTabController(
    length: 2,
    child: new Scaffold(
        appBar: AppBar(
          title: Text(''),
          bottom: TabBar(tabs: [
            Tab(icon: FaIcon(FontAwesomeIcons.calendarCheck), text: "One"),
            Tab(icon: FaIcon(FontAwesomeIcons.tasks), text: "Two"),
          ]),
        ),
        body: SafeArea(
            child: TabBarView(children: [
          Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Expanded(
                child: Scaffold(
                  body: ListView.builder(
                      itemCount: _editorChannels == null
                          ? 0
                          : _editorChannels.length,
                      itemBuilder: (context, index) {
                        final item = _editorChannels[index];
                        return Card(
                          shadowColor: Colors.black26,
                          margin: EdgeInsets.all(3.0),
                          clipBehavior: Clip.antiAlias,
                          shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(2),
                          ),
                          child: ListTile(
                              title: Container(
                                  child: Text(
                                item.Name != null ? item.Name : '',
                                style: new TextStyle(
                                    fontWeight: FontWeight.bold,
                                    fontSize: 16.0),
                              )),
                              subtitle: Text(item.Url),
                              onTap: () => {},
                              isThreeLine: false,
                              leading: getIconbyId(item.Status),
                              
                              

                               //Pass callback   
                              trailing: PopMenuWidget2(
                                onDelete: delete(item),
                              )),


                        );
                      }),
                ),
              )
            ],
          ),
        ]))));
    }
  }

要使 setState() 正常工作,您需要将 PopMenuWidget2 作为 StatefulWidget。变化

class PopMenuWidget2 extends StatelessWidget {

class PopMenuWidget2 extends StatefulWidget {

还有 向你传递回调函数,比如 link ,而不是函数执行的结果 onDelete: () => onDelete(item)

  trailing: PopMenuWidget(
  onDelete: () => onDelete(item),
  )),

完整代码:

class PopMenuWidget2 extends StatefulWidget {
  final VoidCallback onDelete;

  const PopMenuWidget2({Key key, this.onDelete}) : super(key: key);
  @override
  _PopMenuWidget2State createState() => _PopMenuWidget2State();
}

class _PopMenuWidget2State extends State<PopMenuWidget2> {
  @override
  Widget build(BuildContext context) => PopupMenuButton<int>(
    onSelected: (result) {
      //On View
      if (result == 0) {}
      //On Edit
      if (result == 1) { }

      //OnDelete Callback run
      if (result == 2) {
        onDelete();
      }
    },
    itemBuilder: (context) => [
      PopupMenuItem(
        value: 0,
        child: Row(
          children: <Widget>[
            Icon(
              Icons.remove_red_eye_rounded,
              color: Colors.black38,
            ),
            Text('  View Option', style: TextStyle(color: Colors.black38)),
          ],
        ),
      ),
      PopupMenuItem(
        value: 1,
        child: Row(
          children: <Widget>[
            Icon(
              Icons.create,
              color: Colors.black38,
            ),
            Text('  Edit Option', style: TextStyle(color: Colors.black38)),
          ],
        ),
      ),
      PopupMenuItem(
        value: 2,
        child: Row(
          children: <Widget>[
            Icon(
              Icons.delete,
              color: Colors.black38,
            ),
            Text('  Delete Option',
                style: TextStyle(color: Colors.black38)),
          ],
        ),
      ),
    ],
  );
}

您必须定义自定义类型,而不是使用 VoidCallback

typedef MyCustomCallback<T> = void Function(T value);

并将 onDelete 定义更改为:

      final MyCustomCallback onDelete;

最终将回调调用修复为:

      if (result == 2) {
        onDelete(value);
      }
      
      // ...

      trailing: PopMenuWidget2(
        onDelete: (item) => delete(item),
      )),