alibaba / fish-redux

An assembled flutter application framework.
https://github.com/alibaba/fish-redux
Apache License 2.0
7.33k stars 844 forks source link

升级了fish-redux0.1.8之后 程序报错 #243

Closed CoolBerry closed 5 years ago

CoolBerry commented 5 years ago

E/flutter (28347): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: setState() or markNeedsBuild() called during build. This ComponentWidget widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase. E/flutter (28347): The widget on which setState() or markNeedsBuild() was called was: E/flutter (28347): ComponentWidget-[](state: ComponentState#eab34)

之前代码都是好好的,升级了之后就报错了。 报错的是在Component的effect里面,Lifecycle.initState的时候执行了一个reducer的时候报错的,具体更细节的话就是这个component的是appstate下面的一个component的,与appstate有get,set的方法。 怀疑是flutter的这次更新与fish redux的某些逻辑产生了冲突。

多谢解答!

CoolBerry commented 5 years ago

补充一下,我又用我们fish redex的example测试了一下,似乎是通过dependencies 然后 slots 这样子的component的里面的effect,在initState这个生命周期时候就没法dispatch来更新state,不论这个state的field是否与page的state有get,set关系,都不行。 自定义的action应该OK,其他生命周期函数还没有测。

具体测试细节就是我把example里面的report_component加了一个effect,reducer,action,然后在effect里面尝试在init时候去通过reducer更新report state。我后来又在state里面加了一个新的field,尝试上述操作也不work。

CoolBerry commented 5 years ago

更新一下,好像是fish-redux0.1.8的问题,回退到0.1.7之后报错消失。暂时是这样,flutter我也回退到最新的一个stable版本,1.5.4hotfix2版本。之后的不清楚情况,可能跟flutter关系不大。

zjuwjf commented 5 years ago

非常感谢反馈。

bool isInSuitablePhase() {
    return SchedulerBinding.instance != null &&
        SchedulerBinding.instance.schedulerPhase !=
            SchedulerPhase.persistentCallbacks &&
     /// 新增条件
        !(SchedulerBinding.instance.schedulerPhase == SchedulerPhase.idle &&
            WidgetsBinding.instance.renderViewElement == null);
  }

我们知道Redux的数据流是, action -> middleware -> reducer -> state-change -> notify

而fish-redux 会根据 binding里的状态(当前是否适合做UI刷新)来确定,是立即通知刷新还是在下一帧通知刷新,(如果是下一帧通知,会讲这期间的通知汇总为一次batch操作)。

通过这样的机制,我们能保证

而之前判断当前是否适合做UI刷新的逻辑是:

bool isInSuitablePhase() {
    return SchedulerBinding.instance != null &&
        SchedulerBinding.instance.schedulerPhase !=
            SchedulerPhase.persistentCallbacks;
  }

但是这里有一个极小的漏洞,当flutter创建第一个root-element的期间,存在特烈条件,SchedulerBinding.instance.schedulerPhase == SchedulerPhase.idle。

所以当我们在第一个页面第一个element创建完成前,我们将不能setState。

0.1.7 能work是因为里面有一段try-catch,设计上是不需要的,所以在0.1.8中移除了try-catch。

再次感谢反馈,目前已经修复了。