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.
reactjs
add a comment |
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.
reactjs
add a comment |
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.
reactjs
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.
reactjs
reactjs
asked Apr 17 '16 at 14:23
mathanmathan
5128
5128
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
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.
1
Nice! This solution actually works really well for us. We can import all libraries (the different paths in the example above) and pass the desired library as props. PS. For some reason I could not get the export CompA from "./comp_a" to work, had to first import them, and them export them in an json object.
– mathan
Apr 17 '16 at 18:35
@mathan one liner export is part of babel stage-1 preset : export-extensions
– Gabriel Bleu
Nov 22 '17 at 17:17
add a comment |
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.
add a comment |
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>
))}
Thanks! In your example, can I split out views/index.js to a seperate npm package? For example can it be located in another yarn workspace or npm link package?
– mathan
Dec 7 '18 at 22:43
@mathan In the separate package, create an array in containing the names of your desired components. You'll then export that array as follows:module.exports = myArray
. Inviews/index.js
import the package and loop over the exported array, interpolating the array values into the loop output. That should work for you.
– Andy Hoffman
Dec 9 '18 at 10:27
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f36677739%2freact-dynamic-import-jsx%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
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.
1
Nice! This solution actually works really well for us. We can import all libraries (the different paths in the example above) and pass the desired library as props. PS. For some reason I could not get the export CompA from "./comp_a" to work, had to first import them, and them export them in an json object.
– mathan
Apr 17 '16 at 18:35
@mathan one liner export is part of babel stage-1 preset : export-extensions
– Gabriel Bleu
Nov 22 '17 at 17:17
add a comment |
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.
1
Nice! This solution actually works really well for us. We can import all libraries (the different paths in the example above) and pass the desired library as props. PS. For some reason I could not get the export CompA from "./comp_a" to work, had to first import them, and them export them in an json object.
– mathan
Apr 17 '16 at 18:35
@mathan one liner export is part of babel stage-1 preset : export-extensions
– Gabriel Bleu
Nov 22 '17 at 17:17
add a comment |
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.
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.
edited Nov 24 '18 at 8:01
Andy Hoffman
6,64631537
6,64631537
answered Apr 17 '16 at 14:47
gor181gor181
9231611
9231611
1
Nice! This solution actually works really well for us. We can import all libraries (the different paths in the example above) and pass the desired library as props. PS. For some reason I could not get the export CompA from "./comp_a" to work, had to first import them, and them export them in an json object.
– mathan
Apr 17 '16 at 18:35
@mathan one liner export is part of babel stage-1 preset : export-extensions
– Gabriel Bleu
Nov 22 '17 at 17:17
add a comment |
1
Nice! This solution actually works really well for us. We can import all libraries (the different paths in the example above) and pass the desired library as props. PS. For some reason I could not get the export CompA from "./comp_a" to work, had to first import them, and them export them in an json object.
– mathan
Apr 17 '16 at 18:35
@mathan one liner export is part of babel stage-1 preset : export-extensions
– Gabriel Bleu
Nov 22 '17 at 17:17
1
1
Nice! This solution actually works really well for us. We can import all libraries (the different paths in the example above) and pass the desired library as props. PS. For some reason I could not get the export CompA from "./comp_a" to work, had to first import them, and them export them in an json object.
– mathan
Apr 17 '16 at 18:35
Nice! This solution actually works really well for us. We can import all libraries (the different paths in the example above) and pass the desired library as props. PS. For some reason I could not get the export CompA from "./comp_a" to work, had to first import them, and them export them in an json object.
– mathan
Apr 17 '16 at 18:35
@mathan one liner export is part of babel stage-1 preset : export-extensions
– Gabriel Bleu
Nov 22 '17 at 17:17
@mathan one liner export is part of babel stage-1 preset : export-extensions
– Gabriel Bleu
Nov 22 '17 at 17:17
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
answered Nov 22 '17 at 16:08
cristianzamarcristianzamar
9810
9810
add a comment |
add a comment |
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>
))}
Thanks! In your example, can I split out views/index.js to a seperate npm package? For example can it be located in another yarn workspace or npm link package?
– mathan
Dec 7 '18 at 22:43
@mathan In the separate package, create an array in containing the names of your desired components. You'll then export that array as follows:module.exports = myArray
. Inviews/index.js
import the package and loop over the exported array, interpolating the array values into the loop output. That should work for you.
– Andy Hoffman
Dec 9 '18 at 10:27
add a comment |
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>
))}
Thanks! In your example, can I split out views/index.js to a seperate npm package? For example can it be located in another yarn workspace or npm link package?
– mathan
Dec 7 '18 at 22:43
@mathan In the separate package, create an array in containing the names of your desired components. You'll then export that array as follows:module.exports = myArray
. Inviews/index.js
import the package and loop over the exported array, interpolating the array values into the loop output. That should work for you.
– Andy Hoffman
Dec 9 '18 at 10:27
add a comment |
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>
))}
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>
))}
edited Nov 25 '18 at 5:07
answered Nov 25 '18 at 1:29
Andy HoffmanAndy Hoffman
6,64631537
6,64631537
Thanks! In your example, can I split out views/index.js to a seperate npm package? For example can it be located in another yarn workspace or npm link package?
– mathan
Dec 7 '18 at 22:43
@mathan In the separate package, create an array in containing the names of your desired components. You'll then export that array as follows:module.exports = myArray
. Inviews/index.js
import the package and loop over the exported array, interpolating the array values into the loop output. That should work for you.
– Andy Hoffman
Dec 9 '18 at 10:27
add a comment |
Thanks! In your example, can I split out views/index.js to a seperate npm package? For example can it be located in another yarn workspace or npm link package?
– mathan
Dec 7 '18 at 22:43
@mathan In the separate package, create an array in containing the names of your desired components. You'll then export that array as follows:module.exports = myArray
. Inviews/index.js
import the package and loop over the exported array, interpolating the array values into the loop output. That should work for you.
– Andy Hoffman
Dec 9 '18 at 10:27
Thanks! In your example, can I split out views/index.js to a seperate npm package? For example can it be located in another yarn workspace or npm link package?
– mathan
Dec 7 '18 at 22:43
Thanks! In your example, can I split out views/index.js to a seperate npm package? For example can it be located in another yarn workspace or npm link package?
– mathan
Dec 7 '18 at 22:43
@mathan In the separate package, create an array in containing the names of your desired components. You'll then export that array as follows:
module.exports = myArray
. In views/index.js
import the package and loop over the exported array, interpolating the array values into the loop output. That should work for you.– Andy Hoffman
Dec 9 '18 at 10:27
@mathan In the separate package, create an array in containing the names of your desired components. You'll then export that array as follows:
module.exports = myArray
. In views/index.js
import the package and loop over the exported array, interpolating the array values into the loop output. That should work for you.– Andy Hoffman
Dec 9 '18 at 10:27
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f36677739%2freact-dynamic-import-jsx%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown