在 React 中使用 @loadable/component 从外部脚本加载函数
Load function from external script using @loadable/component in React
我有一个 JSON 文件,其中包含多个脚本文件路径,我希望能够将这些脚本动态加载到我的 React 应用程序中,以根据元数据中的规范构建每个组件。目前我的应用程序中有元数据作为 Metadata
数据对象。
metadata.json:
{
"component1": { "script": "./createFirstLayer.js" },
"component2": { "script": "./createSecondLayer.js" }
}
每个脚本导出一个我希望能够用来构建组件的函数。出于故障排除的目的,它目前只有 returns 一条简单的消息。
function createFirstLayer(name) {
return name + " loaded!";
}
export default createFirstLayer;
我做了一些研究并确定了@loadable/component 包。将此包用作 import loadable from "@loadable/component";
,我试图将我的脚本加载到 App.js 中,如下所示:
async componentDidMount() {
Object.keys(Metadata).forEach(function(name) {
console.log(Metadata[name].script);
var createLayer = loadable(() => import(Metadata[name].script));
var message = createLayer(name);
console.log(message);
});
}
我尝试的所有操作都会抛出 TypeError createLayer is not a function
。如何加载函数?
我也尝试过lazy方法。
我已经重新创建了我的问题的工作演示 here。
编辑:我试图将它放在我的应用程序的顶部
const scripts = {};
Object.keys(Metadata).forEach(async function(name) {
import(Metadata[name].script).then((cb) => scripts[name] = cb);
});
这会导致 TypeError 未处理的拒绝(错误):找不到模块“./createFirstLayer.js”。 (匿名函数)
src/components lazy /^.*$/ groupOptions: {} 命名空间 object:66
我也尝试过
const scripts = {};
Object.keys(Metadata).forEach(async function(name) {
React.lazy(() => import(Metadata[name].script).then((cb) => scripts[name] = cb));
});
我的目标是能够调用适当的函数来创建特定层,并在元数据中匹配它们。
您不需要 @loadable/component
有两个原因。
- 您可以通过动态导入实现您的目标
- '@loadable/component' returns 一个 React 组件对象,而不是你的函数。
要使用动态导入,只需按原样解析 JSON,但将对导入默认函数的调用推送到 state
。然后你所要做的就是从状态中渲染“层”。
像这样:
import React, { Component } from "react";
import Metadata from "./metadata.json";
class App extends Component {
constructor(props) {
super(props);
this.state = { messages: [] };
}
async componentDidMount() {
Object.keys(Metadata).forEach(name=> import(`${Metadata[name].script}`).then(cb =>
this.setState((state, props) => ({ messages: [...state.messages, cb.default(cb.default.name)] }))));
}
render() {
return (
<div className="App">
{this.state.messages.map((m, idx) => (
<h1 key={idx}>{m}</h1>
))}
</div>
);
}
}
export default App;
我有一个 JSON 文件,其中包含多个脚本文件路径,我希望能够将这些脚本动态加载到我的 React 应用程序中,以根据元数据中的规范构建每个组件。目前我的应用程序中有元数据作为 Metadata
数据对象。
metadata.json:
{
"component1": { "script": "./createFirstLayer.js" },
"component2": { "script": "./createSecondLayer.js" }
}
每个脚本导出一个我希望能够用来构建组件的函数。出于故障排除的目的,它目前只有 returns 一条简单的消息。
function createFirstLayer(name) {
return name + " loaded!";
}
export default createFirstLayer;
我做了一些研究并确定了@loadable/component 包。将此包用作 import loadable from "@loadable/component";
,我试图将我的脚本加载到 App.js 中,如下所示:
async componentDidMount() {
Object.keys(Metadata).forEach(function(name) {
console.log(Metadata[name].script);
var createLayer = loadable(() => import(Metadata[name].script));
var message = createLayer(name);
console.log(message);
});
}
我尝试的所有操作都会抛出 TypeError createLayer is not a function
。如何加载函数?
我也尝试过lazy方法。
我已经重新创建了我的问题的工作演示 here。
编辑:我试图将它放在我的应用程序的顶部
const scripts = {};
Object.keys(Metadata).forEach(async function(name) {
import(Metadata[name].script).then((cb) => scripts[name] = cb);
});
这会导致 TypeError 未处理的拒绝(错误):找不到模块“./createFirstLayer.js”。 (匿名函数) src/components lazy /^.*$/ groupOptions: {} 命名空间 object:66
我也尝试过
const scripts = {};
Object.keys(Metadata).forEach(async function(name) {
React.lazy(() => import(Metadata[name].script).then((cb) => scripts[name] = cb));
});
我的目标是能够调用适当的函数来创建特定层,并在元数据中匹配它们。
您不需要 @loadable/component
有两个原因。
- 您可以通过动态导入实现您的目标
- '@loadable/component' returns 一个 React 组件对象,而不是你的函数。
要使用动态导入,只需按原样解析 JSON,但将对导入默认函数的调用推送到 state
。然后你所要做的就是从状态中渲染“层”。
像这样:
import React, { Component } from "react";
import Metadata from "./metadata.json";
class App extends Component {
constructor(props) {
super(props);
this.state = { messages: [] };
}
async componentDidMount() {
Object.keys(Metadata).forEach(name=> import(`${Metadata[name].script}`).then(cb =>
this.setState((state, props) => ({ messages: [...state.messages, cb.default(cb.default.name)] }))));
}
render() {
return (
<div className="App">
{this.state.messages.map((m, idx) => (
<h1 key={idx}>{m}</h1>
))}
</div>
);
}
}
export default App;