Updating/redrawing 具有外部状态更改的 Mithril 组件视图 (Redux)

Updating/redrawing Mithril component views with external state changes (Redux)

秘银新手,但真的很想喜欢它。几周前,我使用 React 和 Redux 编写了演示应用程序以进行状态管理。我还使用了一个库来连接两者,但它一切正常,可以在 http://curiousercreative.com/demos/bankDemo/ 看到。在阅读了 Mithril 并喜欢上了很多我读到的内容后,我决定将同一个演示应用程序翻译成 Mithril + Redux,但我似乎无法将我的 Mithril 安装组件安装到 update/redraw,因此更新了我的Redux 存储(状态)从未反映在 UI 中。从我的应用程序的 js/app.js 行 ~144-162,我有我的 Redux 回调和我的两个顶级 Mithril 组件正在安装并传递我们的状态。

// redraws Mithril whenever an action is dispatched
    store.subscribe(function () {
      console.log('happening');
      m.redraw.strategy('all');
      m.redraw(true);
    });

// Render Mithril
    // content
    m.mount(
      document.getElementById('content'),
      m.component(App, store.getState())
    );

    // nav
    m.mount(
        document.getElementById('navContainer'),
        m.component(Nav, store.getState())
    );

如果您在 http://curiousercreative.com/demos/bankDemo-mithril/ 打开控制台,您会注意到每次单击新的 link 时都会有一个日志条目(这会更改更新 Redux 状态存储的哈希)。您还会在上面的代码中注意到,每次出现该日志时,应该会强制重绘 Mithril,但当然 UI 不会改变。将其行为与上面的 React 演示应用程序进行比较。在应用程序的 js/components.js 文件中,我们的两个顶级组件将此状态对象作为参数并将其传递给它们的子组件。

  var App = {
    controller: function (args) {
      this.activePageId = args.activePageId;
      this.accounts = args.accounts;
      ...

  var Nav = {
    controller: function (args) {
      this.activePageId = args.activePageId;
      this.accounts = args.accounts;
      ...

为什么秘银不重绘?

问题是 getState() 在初始化时只被调用一次,因此组件将始终使用对相同原始静态数据存储快照的引用进行重绘。

安装顶级组件后,它们的控制器将执行,它们的视图将被编译和构建,并可以访问控制器和任何传入的参数。控制器在初始化时只执行一次——当重绘触发时,视图函数会重新执行。这意味着嵌套组件可以传递它们的视图可以访问的新参数,但是安装的(顶级)组件的参数是绑定的,并且因为它们本身不是任何视图的后代,所以它们必须确定自己的逻辑更新参考资料。

看你的代码跳出几个想法:

您可以在 mount 中传入 getState 方法(无需调用它)- Mithril 非常支持在视图中使用函数进行数据输入和检索(如 m.prop 所示,一个用于简单模型管理的内部工具):

var component = {
  view : function( ctrl, accessor ){
    return m( 'p', accessor().value )
  }
}

m.mount( document.body, m.component( component, store.getState ) )

动态选择器属性在属性映射中的阅读效果往往更好。请注意,您可以将选择器字符串 类 与属性映射 类 结合使用。在控制器中声明的 activePage 函数看起来像是一个关注点分离,但由于视图需要有一个特定方法的钩子,该函数明确用于生成类名,逻辑非常简单,你d 通过将该逻辑直接放在视图中,显着降低了复杂性并提高了可读性:

m('div.page', {
  id    : args.id,
  class : args.id === args.activePageId ? 'active' : ''
}, /* ... */ )

请注意,您不需要明确地将虚拟 DOM 子项包装在数组中:您可以按顺序包含它们。实际上,这意味着方括号在 Mithril virtual DOM 语法中是多余的:

m( '.parent',
  m( '.child1' ),
  m( '.child2' )
)