javascript - 不使用邪恶的 eval 动态渲染 React 组件

标签 javascript reactjs eval

我有一个工作解决方案(如下),用于在无法显式加载 React 组件的情况下使用标记中的数据属性动态加载它们。我意识到我使用“eval”从组件注册表中获取动态组件,并且我正在寻找更好的解决方案。

export default class DynamicComponentRenderer {

/**
 * Creates an instance of DynamicComponentRenderer.
 * 
 * @param {object} element The DOM element to make into a component.
 * 
 * @memberOf DynamicComponentRenderer
 */
constructor(element, componentRegistry) {
    Guard.throwIf(element, "element");
    Guard.throwIf(componentRegistry, "componentRegistry");

    this.element = element;
    this.componentName = element.getAttribute("data-react-component");
    this.DynamicComponent = eval(`componentRegistry.${this.componentName}`);
    this.props = {};

    if (!this.DynamicComponent) {
        throw new Error(`Unable to create a component of the name '${this.componentName}'.`)
    }

    Array.prototype.slice.call(element.attributes).filter((attrib) => 
        (attrib.name.includes('data-') && !attrib.name.includes('data-react-component'))
    ).forEach((attrib) => {
        this.props[attrib.name.replace(/data-/i, '').replace(/-[a-z]/, (match) => {
            return match.toUpperCase();
        }).replace(/-/, '')] = attrib.value;
    });
}

/**
 * Renders the dynamic React component.
 * 
 * @returns Rendered HTML.
 * 
 * @memberOf DynamicComponentRenderer
 */
render() {
    ReactDOM.render(React.createElement(this.DynamicComponent, this.props), this.element);
}
}

传入的 componentRegistry 来自组件索引文件,看起来有点像这样......

export default {
    DataList: DataList,
    Form: {
        Buttons : {
             Submit: SubmitButton,
             Cancel: CancelButton
        }
    }
    OwnedAddress: OwnedAddress
}

DynamicComponentRegister 由 JsComponentManager 加载...

import PathManager from "../../SharedJs/path-manager";
import AppComponents from "./components/index.jsx";
import Dynamic from "../../SharedJs/components/dynamic-component-renderer";

export default class JsComponentManager {

    constructor(onLoader, pathManager) {
        this.loader = onLoader;
        this.pathManager = pathManager;
        this.select = {
            reactComponents: () => $(".js-react-component")
        }
    }

    bindComponents() {
        const paths = new PathManager();
        let $reactComponents = this.select.reactComponents()
        if ($reactComponents.length > 0) {
            this.loader.add(this.renderReactComponents, $reactComponents);
        }
    }

    renderReactComponents($elements) {
        $.makeArray($elements).forEach((el) => {
            let dynamicRenderer = new Dynamic(el, AppComponents);
            document.DynamicRenderers = document.DynamicRenderers || [];
            document.DynamicRenderers.push(dynamicRenderer);
            dynamicRenderer.render();
        });
    }
}

PathManager 在当前实例中没有执行任何操作(它允许我询问 URL 并通过 URL 渲染组件,但我目前不这样做)。传递到构造函数的“onLoader”根据 onLoad 事件对事件进行排队。

最佳答案

如果您只是使用 eval 来解析通过某些对象的路径,则可以使用旨在遍历对象的函数。

const traverseInternal = (object, keys, keyIndex) => {
  if (keyIndex >= keys.length) {
    return object;
  }

  return traverseInternal(object[keys[keyIndex]], keys, keyIndex + 1);
};

const traverse = (object, deepKey) => {
  return traverseInternal(object, deepKey.split('.'), 0);
};

然后替换

eval(`componentRegistry.${this.componentName}`);

traverse(componentRegistry, this.componentName);

关于javascript - 不使用邪恶的 eval 动态渲染 React 组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42651398/

相关文章:

javascript - 在 Node js 上将数字转换为大端

javascript - ng 嵌入为 : element vs attribute

javascript - react 主题样式

javascript - Material -ui makeStyles : how to style by tag name?

javascript - 插入的 <script> 标签可以在不使用 JavaScript 中的 eval 的情况下多次运行吗?

javascript - 使用 Javascript 将 xml 加载到类

javascript - 单击排序按钮后数据不会重新呈现

javascript - 如何使用 ReactJS 从列表创建表?

mongodb - mongo --eval() 命令行参数是否也会在 MongoDB 3.x 中被弃用?

javascript - 使用 eval 评估文本区域中的 javascript 片段?