简体   繁体   中英

React: dynamic import jsx

This question related to dynamically importing JSX files into React.

Basically we have one main component that dynamically renders other components based on a structure stored in a database. The dynamic components are stored in a subdirectory "./Components". We statically define the this as:

import CompA  from './Components/CompA';
import CompB  from './Components/CompB';

var components = {
 'CompA': CompA,
 'CompB': CompB
}

and we render them using:

var type = 'CompA' 
var Component = components[type];
...
<Component />

While this works fine, it is a bit too static for us. We have 100+ components (CompA/CompBs) and statically define them does not work.

Is it possible to import all JSX files in "./Compontents" and populate the components-array?

And, what would be really (really) nice would be if we could send the "./Components" path as a prop to the main components. And the main component would use this path to import the .jsx files. Like this:

<MainComponent ComponentPath="./SystemComponents">

Would use "./SystemComponents" as path for .JSX files and:

<MainComponent ComponentPath="./UserComponents">

Would use "./UserComponents" as import path.

What about having a components/index.js with contents:

export CompA from "./comp_a";
export CompB from "./comp_b";

Then you do:

import * as Components from "./components"

then you would use as:

<Components.CompA />
<Components.CompB />
...

Hope this helps.

I doubt you can load anything when sending path through component props, loading of the file should then happen inside the React component lifecycle methods which is not something I would recommend.

To complement @gor181's answer, I can add that export s must be this way:

export { default as CompA } from "./comp_a"; export { default as CompB } from "./comp_b";

Hope this might be helpful.

As of React 16.6.0 , we can lazy-load components and invoke them on-demand.

The Routing

// We pass the name of the component to load as a param
<Switch>
  …
  <Route path="/somewhere/:componentName" component={MyDynamicComponent} />
</Switch>

views/index.js

import { lazy } from 'react';

const SomeView = lazy(() => import('./SomeView'));
const SomeOtherView = lazy(() => import('./SomeOtherView'));

export { SomeView, SomeOtherView };

MyDynamicComponent.js

import React, { Suspense, Component } from 'react';
import { PropTypes } from 'prop-types';
import shortid from 'shortid'; // installed separately via NPM
import * as Views from './views';

class MyDynamicComponent extends Component {
  render() {
    const {
      match: {
        params: { componentName },
      },
    } = this.props;

    const Empty = () => <div>This component does not exist.</div>;
    const dynamicComponent = (() => {
      const MyComponent = Views[`${componentName}View`]
        ? Views[`${componentName}View`]
        : Empty;
      return <MyComponent key={shortid.generate()} />;
    })();

    return (
      <>
        <Suspense fallback={<div>Loading…</div>}>{dynamicComponent}</Suspense>
      </>
    );
  }
}
MyDynamicComponent.propTypes = {
  match: PropTypes.shape({
    params: PropTypes.shape({
      componentName: PropTypes.string.isRequired,
    }),
  }),
};

export default MyDynamicComponent;

Usage

{items.map(item => (
  <NavLink to={`/somewhere/${item.componentName}`}>
    {item.name}
  </NavLink>
))}

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