简体   繁体   中英

Load function from external script using @loadable/component in React

I have a JSON file with several filepaths to scripts that I want to be able to load dynamically into my React app, to build each component based on specifications that are in the metadata. Currently I have the metadata in my app as a Metadata data object.

metadata.json:

{
  "component1": { "script": "./createFirstLayer.js" },
  "component2": { "script": "./createSecondLayer.js" }
}

Each script exports a function that I want to be able to use to construct the component. For troubleshooting purposes, it currently only returns a simple message.

function createFirstLayer(name) {
  return name + " loaded!";
}

export default createFirstLayer;

I did some research and identified the @loadable/component package. Using this package as import loadable from "@loadable/component"; , I attempted to load my script into App.js like this:

  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);
    });
  }

Everything I have tried throws the TypeError createLayer is not a function . How can I get the function loaded?

I have also attempted the lazy method.

I have recreated a working demo of my problem here .

EDIT: I have tried to put this at the top of my app

const scripts = {};
Object.keys(Metadata).forEach(async function(name) {
    import(Metadata[name].script).then((cb) => scripts[name] = cb);
});

This causes the TypeError Unhandled Rejection (Error): Cannot find module './createFirstLayer.js'. (anonymous function) src/components lazy /^.*$/ groupOptions: {} namespace object:66

I have also attempted

const scripts = {};
Object.keys(Metadata).forEach(async function(name) {
    React.lazy(() => import(Metadata[name].script).then((cb) => scripts[name] = cb));
});

My goal is to be able to call the appropriate function to create particular layer, and match them up in the metadata.

You don't need @loadable/component for two reasons.

  1. You can accomplish your goal with dynamic imports
  2. '@loadable/component' returns a React Component object, not your function.

To use dynamic imports simply parse your JSON the way you were, but push the call to the import's default function into state . Then all you have to do is render the " layers " from within the state.

Like this:

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;

Here is the working example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM