从布局组件中的文件加载时如何避免无限循环?

How to escape infinite loop when loading from a file in a layout component?

我正在按照 https://mithril.js.org/simple-application.html and the layout example in http://lhorie.github.io/mithril-blog/better-templates-with-fp.html 中的简单应用示例使用 Mithril JS 构建个人网页。但是我让 运行 进入一个无限循环,其中包含一个需要从文件加载数据的组件。

如果我通过 "vnode.attrs" 将内部文件加载组件传递给它,布局组件不会循环。但是,如果我使用函数中的内部组件构建布局组件,它就会循环。我无法理解其中的区别。

失败示例:

hello.json

{"text": "hello"}

index.html

<!DOCTYPE html>
<body>
    <script src="https://unpkg.com/mithril/mithril.js"></script>
    <script src="index.js"></script>
</body>

index.js

var Hello = {
    loadedObj: {},
    load: function () {
        return m.request({
            method: "GET",
            url: "hello.json",
        }).then(function (result) { Hello.loadedObj = result })
    }
}

var HelloBox = {
    oninit: Hello.load,
    view: function () { return m("div", {}, Hello.loadedObj.text) }
}

var layout = function (comp) {
    return {
        view: function () { return m('div', {}, m(comp)) }
    }
}

var workingLayout = {
    view: function (vnode) { return m('div', {}, m(vnode.attrs.comp)) }
}

m.route(document.body, "/workinghello", {
    "/hello": {
        render: function () {
            console.log("rendering /hello")
            return m(layout(HelloBox))
        }
    },
    "/workinghello": {
        render: function () {
            console.log("rendering /workinghello")
            return m(workingLayout, { comp: HelloBox })
        }
    }
})

此处,路由“/workinghello”有效,但“/hello”进入循环。为什么? “/workinghello”设计对我来说似乎是一种代码味道,因为 "vnode.attrs" 通常仅用于将数据传递给文档中的组件而不是组件本身。有没有办法修复“/hello”或简化“/workinghello”?

初读: layout returns 一个函数,而 workingLayout 似乎只是定义一个函数然后退出(不返回任何内容)。这包括对 m(...) 的调用,但如果对 m(...) 的调用正在调用返回的函数,则您有一个循环。

作为调试的一般好策略,当您有一个工作示例和一个 non-working 示例时,对其中一个进行小的更改,使其更像另一个并进行测试,然后重复,直到行为您正在更改的那个开关具有与您正在更改的那个更相似的行为相同的行为。然后来回切换该更改并测试行为是否随之来回更改,以确认此特定更改是否有所不同。这是制作 minimal reproducible example 的一部分,通常会直接帮助您解决问题。

问题是我对布局组件的误解以及 m.render 的行为方式。 [文档](https://mithril.js.org/route.html#advanced-component-resolution} 的 "Wrapping a Layout Component" 部分解决了这种精确的行为。来自 Hello.load 的响应触发重绘,调用再次渲染 /hello 路由,导致无限循环。我能够使用以下设计清理路由(如文档 link 中所建议)。如果布局组件定义为:

var fixedLayout = {
    view: function(vnode) {
        return vnode.children
    }
}

并且路由器像这样使用组件:

    "/fixedhello": {
        render: function() {
            return m(fixedLayout, m(HelloBox))
        }
    }

没有循环。