草庐IT

dart - 父小部件的 setState 不会更新子部件的值

coder 2023-07-23 原文

我有一个 StatefulWidget,其中有一个包含多个子部件的 ListView。

其中一个 child 是包含一些项目的 GridView

我想要实现的是在从父窗口小部件按下按钮时重建此 GridView 子窗口。该按钮位于 Parent 小部件的 bottomNavigationBar 中。

但是,当我按下按钮时,它应该转到 _resetFilter() 方法,该方法有效。但是 setState() 似乎没有更新 Child 小部件内的 GridView build() 方法。

class ParentState extends State<Parent> {

  // removed for brevity

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(...),
      bottomNavigationBar: BottomAppBar(
        child: new Row(
          children: <Widget>[
            Padding(
                padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 5.0),
                child: SizedBox(
                  onPressed: () {
                    _resetFilter();
                  },
                )
            ),
          ],
        ),
      ),
      body: Container(
        child: Form(
            key: _formKey,
            child: ListView(
              children: <Widget>[
                Column(
                  children: <Widget>[
                    Container(
                      child: Column(
                        children: <Widget>[
                          Container(...), // this works
                          Column(...),
                          Container(...), // this works
                          Container( 
                            child: GridView.count(
                              // ...
                              children:
                                  List.generate(oriSkills.length, (int i) {

                                bool isSkillExist = false;

                                if (_selectedSkills.contains(rc.titleCase)) {
                                  isSkillExist = true;
                                } else {
                                  isSkillExist = false;
                                }
                                return Child( // this doesn't work
                                  id: oriSkills[i]['id'],
                                  name: oriSkills[i]['description'],
                                  skillSelect: isSkillExist, // this boolean showed correct value from the above logic
                                  onChange: onSkillChange,
                                );
                              }),
                            ),
                          ),
                        ],
                      ),
                    )
                  ],
                )
              ],
            )),
      ),
    );
  }

  void _resetFilter() {
    setState(() {
      _theValue = 0.0;
      searchC.text = "";
      _selectedSkills = []; // this is the variable that I'd like the GridView to recreate from.
    });
  }
}

我尝试打印子部件中的字段名称之一,但它始终显示旧值而不是新值。

即使在按下按钮之后,它也会将正确的值传递给 ChildState

class ChildState extends State<Child> {
  final String name;
  final MyCallbackFunction onChange;
  bool skillSelect;
  double size = 60.0;

  ChildState({this.name, this.skillSelect, this.onChange});

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

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

  void setSkillLevel() {
    setState(() {
      if (skillSelect) {
        skillSelect = false;
        onChange(name, false);
      } else {
        skillSelect = true;
        onChange(name, true);
      }
    });
  }

  Color _jobSkillSelect(bool select) {
    print(select); // always print old state instead of new state
    return select ? Color(MyColor.skillLvlOne) : Color(MyColor.skillDefault);
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        child: Column(children: <Widget>[
      InkResponse(
          onTap: setSkillLevel,
          child: Container(
            height: size,
            width: size,
            decoration: BoxDecoration(
              image: DecorationImage(
                colorFilter: ColorFilter.mode(_jobSkillSelect(skillSelect), BlendMode.color),
              ),
            ),
          )),
    ]));
  }
}

在按下重置按钮后,如何更新子小部件以从父小部件更新值?

最佳答案

您可能希望将值传递给实际的子类。 到它的状态。
一旦你的 parent 重建,这个类(class)就是重建的。因此,新的值(value)观将得到体现。

所以您的 Child 实现应该看起来像这样(不要忘记将 onChange 类型替换为您的自定义函数。

class Child extends StatefulWidget {
  final String name;
  final Function(void) onChange;
  final bool skillSelect;
  final double size;
  final Function(bool) onSkillLevelChanged;

  const Child({Key key, this.name, this.onChange, this.skillSelect, this.size, this.onSkillLevelChanged}) : super(key: key);

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

class _ChildState extends State<Child> {
  Color _jobSkillSelect(bool select) {
    print(select); // always print old state instead of new state
    return select ? Color(MyColor.skillLvlOne) : Color(MyColor.skillDefault);
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: <Widget>[
          InkResponse(
              onTap: () {
                if (widget.onSkillLevelChanged != null) {
                  widget.onSkillLevelChanged(!widget.skillSelect);
                }
              },
              child: Container(
                height: widget.size,
                width: widget.size,
                decoration: BoxDecoration(
                  image: DecorationImage(
                    colorFilter: ColorFilter.mode(_jobSkillSelect(widget.skillSelect), BlendMode.color),
                  ),
                ),
              )),
        ],
      ),
    );
  }
}

在这种情况下,Child 不再负责管理其 skillSelect 属性。它只是在其父级上调用一个 Function。然后父级使用新的 skillSelect bool 值构建。

所以你可以像这样使用这个 child :

return Child( // this doesn't work
   id: oriSkills[i]['id'],
   name: oriSkills[i]['description'],
   skillSelect: oriSkills[i]['isSkillExist'], 
   onChange: onSkillChange,
   onSkillLevelChanged: (newSkillLevel) {
      setState(() {
         oriSkills[i]['isSkillExist'] = newSkillLevel;
      });
   },
);

关于dart - 父小部件的 setState 不会更新子部件的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55611705/

有关dart - 父小部件的 setState 不会更新子部件的值的更多相关文章

  1. ruby - Highline 询问方法不会使用同一行 - 2

    设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案

  2. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  3. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

  4. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  5. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  6. ruby - 获取数组中的值并最小化某个类属性的最优雅的方法是什么? - 2

    假设我有以下类(class):classPersondefinitialize(name,age)@name=name@age=ageenddefget_agereturn@ageendend我有一组Person对象。是否有一种简洁的、类似于Ruby的方法来获取最小(或最大)年龄的人?如何根据它对它们进行排序? 最佳答案 这样做会:people_array.min_by(&:get_age)people_array.max_by(&:get_age)people_array.sort_by(&:get_age)

  7. ruby-on-rails - 使用作为方法的值在 ruby​​ 中搜索哈希 - 2

    我在搜索我的值是方法的散列时遇到问题。我只是不想运行plan_type与键匹配的方法。defmethod(plan_type,plan,user){foo:plan_is_foo(plan,user),bar:plan_is_bar(plan,user),waa:plan_is_waa(plan,user),har:plan_is_har(user)}[plan_type]end目前如果我传入“bar”作为plan_type,所有方法都会运行,我怎么能只运行plan_is_bar方法呢? 最佳答案 这个变体怎么样?defmethod

  8. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  9. ruby-on-rails - prawnto 显示新页面时不会中断的表格 - 2

    我有可变数量的表格和可变数量的行,我想让它们一个接一个地显示,但如果表格不适合当前页面,请将其放在下一页,然后继续。我已将表格放入事务中,以便我可以回滚然后打印它(如果高度适合当前页面),但我如何获得表格高度?我现在有这段代码pdf.transactiondopdf.table@data,:font_size=>12,:border_style=>:grid,:horizontal_padding=>10,:vertical_padding=>3,:border_width=>2,:position=>:left,:row_colors=>["FFFFFF","DDDDDD"]pdf.

  10. ruby - 从 sinatra 中的 before do block 返回不同的值 - 2

    有没有办法在sinatra的beforedoblock中停止执行并返回不同的值?beforedo#codeishere#Iwouldliketo'return"Message"'#Iwouldlike"/home"tonotgetcalled.end//restofthecodeget'/home'doend 最佳答案 beforedohalt401,{'Content-Type'=>'text/plain'},'Message!'end如果你愿意,你可以只指定状态,这里有状态、标题和正文的例子

随机推荐