我需要动态加载react组件。
我得到要从用户加载为字符串的组件的名称。我使用 webpack 。
如何动态加载组件而不是静态导入语句。似乎Require.Ensure
没有评估表达式。我想要实现的是这样的。
require.ensure([ "./widgets/" + componentName ] ,(require) => {
let Component = require("./widgets/" + componentName);
});
但这似乎不起作用。
答案 0 :(得分:16)
基本上它归结为预先创建你需要的所有块。那么你只需要一种动态引用它们的方法。以下是我所依据的解决方案:
http://henleyedition.com/implicit-code-splitting-with-react-router-and-webpack
这就是我所做的事情,因为我不使用React Router(旁注:我发现它不适合还原或动画):
//loader:
{
test: (folder)\/.*\.js,
include: path.resolve(__dirname, 'src')
loader: ['lazy?bundle', 'babel']
}
//dynamic usage within React component:
const My_COMPONENTS = {
ComponentA: require('./folder/ComponentA'),
ComponentB: require('./folder/ComponentB'),
}
class ParentComponent extends React.Component {
componentDidMount() {
My_COMPONENTS[this.props.name](component => this.setState({component}));
}
render() {
return <this.state.component />;
}
}
因此,结果是您正在动态呈现一个组件,但是从一组静态预定的可能性开始 - 同时,只发送给客户端而不是访问者实际感兴趣的块。
另外,这里有一个我做得很好的组件:
import React from 'react';
import Modal from './widgets/Modal';
export default class AjaxModal extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
Content: null
};
}
componentDidMount() {
if(this.props.show) {
this.loadContent();
}
}
componentWillReceiveProps({show}) {
if(show && !this.state.Content) {
this.loadContent(1200); //dont interfere with animation
}
}
loadContent(ms=0) {
setTimeout(() => {
this.props.requestLazyBundle(({default: Content}) => {
this.setState({Content});
});
}, ms);
}
render() {
let {Content} = this.state;
return (
<Modal title={this.props.title} {...this.props} loading={!Content}>
{Content ? <Content /> : null}
</Modal>
);
}
}
传递async require bundler函数this.props.requestLazybundle
,如下所示:
render() {
let requestLazyBundle = require('bundle?lazy&name=AnotherComponent!../content/AnotherComponent');
return (
<AjaxModal title='Component Name' {...props} requestLazyBundle={requestLazyBundle} />
);
}
答案 1 :(得分:6)
请查看我为完整源代码提供的这个主页 https://gist.github.com/SamanShafigh/a0fbc2483e75dc4d6f82ca534a6174d4
因此,假设您有4个名为D1,D2,D3的组件。您需要的是创建依赖注入和依赖容器机制。这是一个非常简单的实现
想象一下,您有一个这样的配置文件来定义您的组件
export default [
{
name:'D1',
path:'D1'
},
{
name:'D2',
path:'D2'
},
{
name:'D3',
path:'D3'
}];
然后你可以有一个这样的组件容器
import componentsConfig from 'ComponentsConfig';
let components = {};
for (var i = 0; i < componentsConfig.length; i++) {
let componentConfig = componentsConfig[i];
// Check if component is not already loaded then load it
if (components[componentConfig.name] === undefined) {
components[componentConfig.name] = require(`${componentConfig.path}`).default;
}
}
export default components;
最后,在您要加载组件的位置,您可以使用组件容器动态加载组件,或者换句话说,您可以注入组件
import React, { Component } from 'react';
import ComponentContainer from './ComponentContainer';
class App extends Component {
render() {
let components = ['D1', 'D2', 'D3'];
return (
<div>
<h2>Dynamic Components Loading</h2>
{components.map((componentId) => {
let Component = ComponentContainer[componentId];
return <Component>{componentId}</Component>;
})}
</div>
);
}
}
export default App;
答案 2 :(得分:1)
import React, { Component } from "react";
class DynamicLoader extends Component {
render() {
const COMPONENTS = {
CompA: require('./CompA'),
CompB: require('./CompB'),
}
if(this.props.component && COMPONENTS[this.props.component]) {
let Component = COMPONENTS[this.props.component].default;
return <Component />
}
}
}
export default DynamicLoader;
<DynamicLoader component="CompA" />
答案 3 :(得分:1)
截至React 16.6.0(2018年10月23日),React.lazy()
可能是一种方便的解决方案,在code-splitting的旗帜下进行了客户端渲染。
给出您希望延迟加载的以下组件(MyLazy.js
:
import React from 'react';
export default function (props) {
return (
<p>My component</p>
);
}
您可以使用以下内容从另一个组件(例如App.js
)进行渲染,请注意,内置<Suspense>
组件将一直显示直到加载完成:
import React, { Suspense } from 'react';
export function App(props) {
const MyLazyLoaded = React.lazy(() => import('./MyLazy'));
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<MyLazyLoaded />
</Suspense>
</div>
);
}
如果要动态设置组件的名称,例如根据用户输入的问题,可以将import语句设置为变量,例如:
var lazyComponentName = 'MyLazy';
const MyLazyLoaded = React.lazy(() => import('./' + lazyComponentName));
请注意,如果您没有串联并直接使用变量名(即import(lazyComponentName)
),则会看到与webpack相关的以下ES Lint警告:
关键依赖项:依赖项的请求是一个表达式
答案 4 :(得分:0)
我的问题有所不同,因此我有一个不同的解决方案,我寻找了一段时间的答案,但找不到答案。希望这可以对某人有所帮助。
我的问题是我们在核心UI中将多个应用程序作为不同的模块独立部署。这些必须完全独立部署,以对其他任何方面都没有影响。
我的解决方案是通过设置以下Webpack属性,将子组件应用程序包装为Web Pack库:
libraryTarget: 'umd',
globalObject: 'this',
library: 'SubComponentName'
我认为基于直接访问或通过单独应用程序中的父组件访问应用程序,为该应用程序提供了2个入口点
class Library extends Component {
render() {
return (
< Provider store = {store} >< BrowserRouter>
< App isAccessDirect={this.props && this.props.isAccessDirect || false} roles={this.props.roles}>
</App>
< /BrowserRouter>< /Provider>
)
}
}
class Launcher extends Component {
render() {
return (
ReactDOM.render(
<Library isAccessDirect="true"/>,
document.getElementById('root')
)
)
}
}
构建此应用后,我可以直接在index.html中使用
<script>
new Compression.Launcher().render();
</script>
或者,如果您希望按照我的要求通过单独的主机/组件访问应用程序,则可以结合使用loadjs和react来实现。
loadjs(['../sub/component/bundle.min.js'], 'loadSubComponent');
var subComponent = this.getUI('subComponentWrapperElement').get(0);
loadjs.ready('loadSubComponent', function() {
var roles = my.app.roles;
ReactDOM.render(
<SubComponentName.Library roles={roles}></SubComponentName.Library>,
subComponent
);
});
这可以加载到任何类型的javascript客户端框架中的react组件中,在本例中,我们在包装应用程序中使用了主干。 bundle.min.js也位于反向代理后面,但它可以位于任何地方,仅需将其加载并等待加载完成,在这种情况下,loadjs非常适合。最后一点重要信息是,销毁组件对于确保良好的用户体验至关重要,因为我们没有遇到很多问题。
loadjs.reset();
var subComponent = this.getUI('subComponentWrapperElement').get(0);
ReactDOM.unmountComponentAtNode(subComponent);
因此,总的来说,我觉得这提供的是其他完全独立于框架的应用程序套件,这些套件可以与框架完全无关。
答案 5 :(得分:0)
这里有很多好的答案。我发现的另一种方法是将组件延迟加载为微型应用程序。宿主应用程序甚至不需要在设计时安装或导入组件。
import React from 'react';
import ReactDOM from 'react-dom';
import MicroApp from '@schalltech/honeycomb-react-microapp';
const App = () => {
return (
<MicroApp
config={{
View: {
Name: 'redbox-demo',
Scope: 'beekeeper',
Version: 'latest'
}
}}
/>
);
});
export default App;
我通过以下链接进行了实验。这是一个非常有趣的概念。
答案 6 :(得分:0)
我正在寻找解决方案,然后我发现了 react-router npm 包。
https://www.npmjs.com/package/react-loadable
这是我的例子:
动态加载具有名称的组件。首先获取加载项:
const MyComponent = Loadable({
loader: () => import(`../charts/${some_name}`),
loading: () => <div>Loading...</div>,
});
然后你有了它,你可以渲染它:
<MyComponent />
这个阅读也可能有帮助:
https://itnext.io/react-loading-components-dynamically-a9d8549844c4