【问题标题】:ReactJS - Async Dynamic Component LoadingReactJS - 异步动态组件加载
【发布时间】:2020-01-09 13:07:18
【问题描述】:

情况

我从 cms 接收到 json,该 json 描述了需要在任何给定页面上显示的内容。这个项目有 50 多个组件,因此我宁愿根据需要挑选它们,而不是在每个页面上都要求它们。

问题

我该怎么做

  1. 确保所有组件都可以导入(我认为这需要一些 webpack 技巧)
  2. 将 json 的内容节点转换为 jsx 时,确保所描述的任何组件都被渲染出来。

当前想法

我可以遍历原始 jsx 并收集给定页面的所有标签,然后尝试通过类似

的方式加载每个标签
const name = iteration.tagName;
dynCmps[name] = someAsynchronousLoad(path + name);

然后在加载完成时调度一个 redux 事件以启动页面的全新渲染。

至于将原始文本内容转换为反应 js,我正在使用 ReactHtmlParser

迄今为止最好的资源

【问题讨论】:

  • 你是说你从 cms 得到的 json 实际上是 react 组件代码还是只是需要在 react 组件中渲染的内容?如果满足您的需要,您还知道React.lazy 的用法吗?
  • 多半是后者。 CMS 内容采用所见即所得的方式设计,因此输出将包含具有属性/样式的组件。我越深入,我意识到最好的举措就是在运行时将每个可能的组件导入 CMS 所见即所得,即使每个页面上只会使用其中的几个组件(这就是我可能使用 @ 987654326@)
  • @Rikin 我找到了可行的解决方案——我打算再清理一下。无论如何,请看看让我知道你的想法。

标签: reactjs


【解决方案1】:

这让我难过了几天。在与一位同事讨论了一段时间后,我们决定卸载预先加载所有组件的性能损失所需的工作量不适用于我们的 30-50 个组件的场景。

可以使用延迟加载,但我决定不这样做,因为额外的 10 毫秒加载(如果是这样的话)根本不会引起注意。

import SomeComponent from "./SomeComponent.js"

const spoofedComponents = {
    SomeComponent: <SomeComponent />
}

const replaceFunc = (attribs, children) => {
  const keys = Object.keys(spoofedComponents);
  for(var i in keys) {
    const key = keys[i];
    // lower case is important here because react converts everything to lower case during text-to-html conversion - only react components can be camel case whereas html is pascal case.
    if(attribs.name === key.toLowerCase()) { 
      return spoofedComponents[key];
    }
  }

  return <p>unknown component</p>
}

...

//inside render

const raw = "<SomeComponent><SomeComponent />"
// it's VERY important that you do NOT use self-closing tags otherwise your renders will be incomplete.
{parse(raw, {
    replace: replaceFunc
})}

在我的例子中,我导入了 30 多个组件并映射到我的 spoofedComponents 常量。这有点麻烦,但这是必要的,因为 react 需要了解给定情况的所有信息,以便虚拟 dom 可以做它应该做的事情 - 节省显示性能。优点是,现在非开发人员(编辑)可以使用 WYSIWYG 构建布局,并使用开发人员制作的组件进行显示。

干杯!

编辑

我仍然坚持添加自定义道具和孩子。

编辑

基本道具正在使用

const spoofedComponents = {
  SomeComponent: (opts) => {
    let s = {};
    if(opts.attribs.style)
      s = JSON.parse(opts.attribs.style);
    if(opts.attribs.classname) {
      opts.attribs.className = opts.attribs.classname;
      delete opts.attribs.classname;
    }

    return <APIRequest {...opts.attribs} style={s}>{opts.children[0].data}</APIRequest>
  }
}

...

const replaceFunc = (opts) => {
  const keys = Object.keys(spoofedComponents);
  for(var i in keys) {
    const key = keys[i];
    if(opts.name === key.toLowerCase()) { 
      const cmp = spoofedComponents[key](opts);
      return cmp;
    }
  }

  return <p>unknown component</p>
}

现在要弄清楚如何动态添加子组件..

编辑

这已经足够好了,我将保持原样。这是更新后的replaceFunc

const replaceFunc = (obj) => {
  const keys = Object.keys(spoofedComponents);
  for(var i in keys) {
    const key = keys[i];
    if(obj.name === key.toLowerCase()) { 
      if(obj.attribs.style)
        obj.attribs.style = JSON.parse(obj.attribs.style);
      if(obj.attribs.classname) {
        obj.attribs.className = obj.attribs.classname;
        delete obj.attribs.classname;
      }

      return React.createElement(spoofedComponents[key], obj.attribs, obj.children[0].data)
    }
  }

  return obj; //<p>unknown component</p>
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-27
    • 2019-07-21
    • 2020-02-07
    • 2019-02-13
    • 2014-09-23
    相关资源
    最近更新 更多