微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么 Mithril 子组件状态改变不会触发更新?

如何解决为什么 Mithril 子组件状态改变不会触发更新?

以下代码按预期工作:它创建了两个计数器按钮,它们保持其状态并在点击时更新:

let Counter = function (vnode) {
  let count = 0

  return {
    view: (vnode) => {
      return m("button",{
          onclick: function () {
            console.log(count++)
          }
        },"Count: " + count)
    }
  }
}

let Counters = {
  view: () => [
    m(Counter),m(Counter),]
}

m.mount(document.body,Counters)

但是,如果我在单独的变量中定义 Counter 组件数组并将其传递给 Counters 视图函数,则视图将停止更新。状态仍然存在,我可以看到记录到控制台的计数增加,但屏幕上没有任何变化。这是更新后的代码

let Counter = function (vnode) {
  let count = 0

  return {
    view: (vnode) => {
      return m("button","Count: " + count)
    }
  }
}

let counters = 
  [
    m(Counter),]
let Counters = {
  view: () => counters
}

m.mount(document.body,Counters)

为什么会发生这种情况?这是我正在处理的更复杂的 Mithril 应用程序的一个玩具示例,我想在其中对子组件数组进行任意排序。

解决方法

我认为可能发生的情况是,在您设置数组时组件正在“渲染”,因为 JavaScript 评估表达式的方式,counters 数组中的 Mithril 组件在您尝试之前已经执行稍后安装它们,因此 Mithril 重绘机制(通过 m.mountm.route)可能不“知道”这些组件,因此不是重绘队列的一部分。

let counters = 
  [
    m(Counter),m(Counter),]

我不确定您想要实现什么,但也许更好的解决方案是将数据数组保存在纯 JS 数据结构中,当您需要实际渲染组件时,您可以映射数据结构,例如

let Counter = function (vnode) {
  return {
    view: (vnode) => {
      return m("button",{
          onclick: function () {
            console.log(this,vnode.attrs.count++);
          }
        },"Counter #" + vnode.attrs.id +": " + vnode.attrs.count)
    }
  }
}

let counterList = [
  { id: 1,name: "Something 1",count: 0 },{ id: 2,name: "Something 2",{ id: 3,name: "Something 3",]

let reorderCountersByCountAscending = () => {
  counterList.sort((a,b) => (a.count > b.count) ? 1 : -1)
}

let Counters = {
  view: () => {
    return m('div',m('button',{ onclick: reorderCountersByCountAscending },'Reorder Children'),counterList
        .map((counterListItem) => m(Counter,counterListItem))
    )
  }
}

m.mount(document.body,Counters);

这不是一个理想的实现,有很多状态突变以非常隐含的方式发生,它可能会在现实世界的应用程序中导致很多混乱,但我希望它描述了这种方法。

这里还有一些示例供您查看: https://jsfiddle.net/9hu2yd1s/

,

我能够在 Mithril Gitter 聊天中收集有用的反馈,并将在下面发布我学到的东西。

我的示例中的计数器没有更新的原因是因为它们在 counters 数组中定义了一次,随后被返回。由于每次调用 view()Counters 函数时都会返回相同的数组,因此 Counters 认为不需要更新,因为它认为它返回的元素没有改变。即使数组内的 Counter 元素更新,对数组的引用仍然保持不变。

处理此问题的一种方法是定义一个工厂函数,该函数将在每次调用 Counter 上的 view() 函数时返回一个新的 Counters 元素排序数组。此外,应用程序状态需要保存在全局位置,传递给每个 Counter 的唯一参数是它引用的全局计数器的索引,如下所示:

let counterData = [0,0]

let Counter = {
  view: ({
    attrs: {
      index
    }
  }) => {
    return m("button",{
      onclick: () => counterData[index]++
    },"Count: " + counterData[index])
  }
}

let Counters = function () {
  const counters = () => {
    return counterData.sort((a,b) => a - b).map((count,i) => m(Counter,{
      index: i
    },count))
  }

  return {
    view: () => counters()
  }
}

m.mount(document.body,Counters)

可以在 here 中找到一个有效的 JSFiddle。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。