【问题标题】:Custom Render function in JSX - How to handle fragmentsJSX 中的自定义渲染函数 - 如何处理片段
【发布时间】:2020-07-22 15:29:04
【问题描述】:

我正在尝试使用 JSX 本身(没有 React)来呈现一些动态内容,并带有一个自定义的 createElement 函数。我正在使用具有以下设置的 webpack:{ "pragma": "createElement", "pragmaFrag": "'fragment'" } for @babel/plugin-transform-react-jsx

这是我的自定义渲染器代码:

function createElement(tagName, attrs = {}, ...children) {
    let el = document.createElement(tagName);

    if (attrs) {
        for (let [ key, val ] of Object.entries(attrs)) {
            if (key === 'className') {
                el.className = val;
            } else {
                el.setAttribute(key, val);
            }
        }
    }

    for (let child of children) {
        if (Array.isArray(child)) el.append(...child);
        else el.append(child);
    }

    return el;
}

我很好奇如何在这个函数中处理片段元素 (<>content</>)。通过谷歌搜索,我发现人们添加了以下内容:

function createElement() {
  // ...
  if (tagName === 'fragment') return children;
  // ...
  return el;
}

但这只是返回字符串"[object HTMLLIElement]",这对我来说是因为createElement似乎必须返回一个节点元素,而不是NodeList或某种数组。

有没有办法在我的 createElement 函数中轻松实现片段?谢谢

编辑:

使用下面 T.J. 的回答,我能够通过添加以下行来解决问题,以利用 DocumentFragment

    let el = tagName === 'fragment' ? new DocumentFragment() : document.createElement(tagName);

【问题讨论】:

    标签: javascript jsx


    【解决方案1】:

    这在很大程度上取决于您如何处理它,因为您还(可能)编写了使用您的 createElement 返回的代码(例如,将这些东西放入 DOM - 相当于 ReactDOM.render 或类似的) .您可以返回一个数组、document fragment 或您自己的自定义容器。不管是什么,你的代码需要这些并将它们放入 DOM 中,只需要检查它并适当地处理它。

    我应该注意createElement 通常不会直接创建 DOM 元素。它创建的对象(通常)具有创建元素的信息,但不是实际元素。原因之一是您并不总是将这些对象转换为 DOM 元素。如果您正在更新而不是安装,您通常会根据对象中的更新信息更新现有的 DOM 元素。当然,你可以做不同的事情,这里没有“错误”。 :-) 我提到它是因为知道这可能会帮助您解决片段问题。

    【讨论】:

    • 我没有编写调用 createElement 的渲染函数,所以我假设它使用的是 JSX 默认函数,但我一直很难弄清楚它在哪里或者它的样子。但是,我没有意识到 Document.fragment 是一个东西,而且效果很好!
    • @nikarc - 很高兴成功了! FWIW,JSX 与该功能没有任何关系,它只是您拥有的任何 使用 JSX 结果的功能。我很感兴趣你不知道那是什么功能;你是如何在 DOM 中挂载你的代码的?
    • 我想我的困惑是基于我没有在我的代码中直接调用 createElement 的事实,以及我为 plugin-transform-react-jsx 设置 pragma 设置的事实,我只是假设它是 jsx 调用 createElement 函数。我的 jsx 是通过调用:const navigation = Navigation(navData); nodeEl.replaceWith(navigation) 安装的。 Navigation 是我的顶级 jsx,navData 是 json 数据,nodeEl 是一个 DOM 元素
    • @nikarc - 抱歉,我可能让你有点困惑。是的,当您在 JSX 中执行 <div>...</div> 时,您正在调用您的 createElement 函数; JSX 变为 createElement("div", {})。我所说的另一半相当于ReactDOM.render 或类似的。在你的情况下,你相当于 thatnodeEl.replaceWith(navigation)。 :-) 所以你正在获取createElement 的输出并直接在 DOM 中使用它。这与 React 和其他人所做的略有不同;它们有一个中间形式,因此它们可以有效地在 DOM 中的内容之间做出区别......
    • 谢谢 T.J.!我非常感谢这个解释,现在对我来说肯定更有意义。我不需要从我的createElement 函数中重用生成的 dom 元素,因为它只是在站点上用于一个小的导航菜单并且它根本不会渲染很多 JSX。不过我会密切注意,如果我发现任何减速,我会找到另一种解决方案。谢谢!
    猜你喜欢
    • 2020-05-27
    • 1970-01-01
    • 2017-03-10
    • 2018-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-28
    • 1970-01-01
    相关资源
    最近更新 更多