我有一个工作解决方案(如下),用于在无法显式加载 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/