Flutter:如何从Dismissible onDismissed访问上下文

时间:2019-10-14 17:48:44

标签: flutter redux

我正在尝试对Flutter中的Dismissible列表项实施撤消,并且在访问BuildContext时遇到问题。

我有一个扑扑的名单,其中的每个项目都是一张卡片。卡被包裹在Dismissible中,这使用户可以滑动以将其解散。 Dismissible会自动从列表中删除该项目。 Dismissible也有一个onDismissed事件-我正在使用此事件来更新Redux状态存储中的项目(将isDismissed标志设置为true),然后显示一个包含UNDO按钮的SnackBar。

这是我遇到问题的地方。我希望UNDO按钮通过将另一个动作调度到Redux存储以将isDismissed设置为false来恢复该项目。为此,我需要一个上下文,从该上下文可以获取商店调度程序。但是,当我尝试下面的代码时,单击UNDO时出现错误:

  

查找已停用的小部件的祖先是不安全的

class ProductCard extends StatelessWidget {
  final Product product;

  const ProductCard(this.product);

  @override
  Widget build(BuildContext context) {
    return Dismissible(
      key: Key(product.id.toString()),

      onDismissed: (direction) {
        StoreProvider.of<AppState>(context).dispatch(DismissAction(product));

        // Then show a snackbar to allow undo
        Scaffold.of(context).showSnackBar(
            SnackBar(
                content: Row(
                  children: <Widget>[
                    Expanded(child: Text("Dismissed ${product.title}"),),
                    FlatButton(
                      onPressed: () {
                        // THIS IS WHERE I GET THE ERROR
                        StoreProvider.of<AppState>(context).dispatch(UndoDismissAction(product));
                      },
                      child: Text("UNDO"),
                    )
                  ],
                )
            )
        );
      },

      child: Card(
        child: ...
      )
    );
  }
}

从我的阅读中,我认为正在发生的事情是撤消按钮的onPressed动作中的行StoreProvider.of<AppState>(context)试图使用属于Card的上下文,但是因为该Card已被删除从列表中删除,它不再存在。

我不确定该如何解决。我已经阅读了有关颤振键的信息,并认为答案可能是开始传递某种全局键,但是我无法完全理解它是如何工作的。我试了一下,遇到了'inheritFromWidgetOfExactType' was called on null的另一个问题。钥匙是否可以解决此问题?如果是这样,我应该在哪里创建密钥,我应该将其传递到小部件中,应该使用哪种类型的密钥等等,或者有更好的解决方案?

非常感谢!

1 个答案:

答案 0 :(得分:0)

将商店的单个副本提取到局部变量中,然后该变量将被下面的所有lambda捕获。

  @override
  Widget build(BuildContext context) {
    var store = StoreProvider.of<AppState>(context);
    return Dismissible(
    ...
         store.dispatch(DismissAction(product));