在这篇文章中,我们将研究如何从ember.js应用程序调用React组件。在研究主题之前,让我们快速介绍这两个框架(或库),看看为什么我们要首先将React集成到Ember Codebase中。
余烬
Ember是雄心勃勃的网络开发人员的框架。这是一个富有成效的战斗测试JavaScript框架,用于构建现代网络应用程序。它包括您构建在任何设备上工作的丰富UI所需的一切。它已经存在了10多年,并且仍然受到许多公司的优先和使用。
反应
React当然并不需要介绍,因为它是JavaScript框架空间中无可争议的领导者。它是用于构建用户界面的JavaScript库。它是基于声明性和组成部分的。使用React,您可以构建封装的组件来管理自己的状态,然后构成它们以制造复杂的UI。
为什么?
可能有许多理由将REACT集成到ember.js应用程序中,从性能,可维护性,技术异质性,组织原因,开发人员可用性为业务优先级。我的Emberanos同胞在这些原因上不会完全同意我的看法。没关系。但是,我想分享我在最近进行的一些实验中分享我的知识,以帮助更大的人社区以及那些希望从Ember迁移到反应的人。
重要的是要记住,Ember并不是一个坏框架。在JavaScript框架方面,Ember仍然是我的初恋。 。您真的无法将Ember与React绝对术语进行比较。因为它是苹果和橙子。
设置monorepo
我们将为这篇文章设置一个monorepo。这使我们有一个明确的优势,即将React组件和Ember应用程序分别保留在单个存储库中。我们将使用pnpm workspaces进行手头的任务。
|-app
|--|-<Ember app>
|-some-react-lib
|--hello-world.jsx
|--package.json
|-README.md
|-pnpm-lock.yaml
|-pnpm-workspace.yaml
这是我使用命令行设置monorepo结构的方式。
mkdir ember-react-example
cd ember-react-example
touch README.md pnpm-workspace.yaml
mkdir app some-react-lib
cd app
degit ember-cli/ember-new-output#v4.10.0
cd ..
cd some-react-lib
touch hello-world.jsx package.json
在这里,我正在使用degit来引导我们的ember应用程序,因为ember-cli
不允许您以app
的名义创建一个新的ember应用。
我们的pnpm-workspace.yaml
文件应该看起来像这样的东西,表明工作区包含两个软件包一个ember应用程序和其他react组件库。
packages:
- app
- some-react-lib
编译用灰烬的反应组件
现在,我们将看到如何使用ember-auto-import
配置Ember Build Pipeline,以调整下面的WebPack构建器以编译JSX。在此之前,我们需要添加适当的依赖项,以编译react
和react-dom
本身和其他babel插件(例如React)。
因此,从您的Ember App root文件夹中,运行以下命令以添加依赖项。
pnpm add -D react react-dom babel-loader @babel/preset-react
这是Ember应用程序内的修改后的ember-cli-build.js
文件的样子。我们正在配置WebPack加载程序,以从Monorepo内的React软件包some-react-lib
处理所有JSX。
'use strict';
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function (defaults) {
let app = new EmberApp(defaults, {
autoImport: {
webpack: {
module: {
rules: [
{
test: /some-react-lib\/.*\.jsx/,
use: {
loader: 'babel-loader',
options: {
presets: [['@babel/preset-react', { runtime: 'automatic' }]],
},
},
},
],
},
},
}
});
return app.toTree();
};
通过修饰符渲染组件
修饰符是与Ember中DOM相互作用的基本原始性。例如,Ember带有内置修饰符{{on}}
:
<button {{on "click" @onClick}}>
{{@text}}
</button>
所有修饰符都会直接应用于元素(如果您看到不在元素中的相似值,则可能是助手),并且在应用其效果时将通过元素传递。
从概念上讲,修饰符采用跟踪,派生状态并将其转变为某种副作用,以某种方式与它们应用于。
要创建我们的修饰符,我们将在Ember应用程序中使用ember-modifier
插件。让我们首先安装我们的插件。
ember install ember-modifier
让我们创建一个基于类的修饰符来渲染我们的React组件。
ember g modifier react --class
这是新创建的修饰符的代码。基本上,修饰符正在尝试为React组件创建一个新的根元素,然后创建一个React组件的新实例,并将其在修饰符提供的元素中渲染。 @ember/destroyable
中可用的registerDestructor
功能将帮助您拆除修饰符时添加的功能。
import Modifier from 'ember-modifier';
import { createRoot } from 'react-dom/client';
import { createElement } from 'react';
import { registerDestructor } from '@ember/destroyable';
export default class ReactModifier extends Modifier {
modify(element, [reactComponent], props) {
if (!this.root) {
this.root = createRoot(element);
registerDestructor(this, () => this.root.unmount());
}
this.root.render(createElement(reactComponent, { ...props }));
}
}
反应组件
我们的React组件是一个简单的组件,显示可以使用Ember组件的动作来切换消息的消息。
这是我们的React组件的代码。
export function HelloWorld({ message, onClick }) {
return <div>
<button onClick={onClick}>Toggle</button>
<div>you said: {message}</div>
</div>;
}
创建Ember包装组件
让我们创建我们的包装组件,为此我们需要一个带有类的微光组件
ember g component example -gc
ember component.js
Ember包装组件的代码很简单。首先,我们是从MonorePo中的共享库中导入React组件,并将其分配给称为theReactComponent
的组件属性,我们将将主要参数使用给修饰符。然后,我们有一个跟踪的属性消息和一个动作切换,这两个都构成了React组件。
import { HelloWorld } from 'some-react-lib/hello-world.jsx';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
export default class extends Component {
theReactComponent = HelloWorld;
@tracked message = 'hello';
@action toggle() {
if (this.message === 'hello') {
this.message = 'goodbye';
} else {
this.message = 'hello';
}
}
}
Ember组件模板
这就是我们在DOM元素上使用react
修饰符来渲染我们的React组件并通过道具传递数据。
<div {{react this.theReactComponent message=this.message onClick=this.toggle}} />
这就是Ember应用的样子。基本上,我们正在使用按钮切换一条消息。消息数据和消息处理程序功能都通过修饰符道具从Ember传递到React组件。
优点缺点
在Ember应用程序中使用了React组件后,让我们讨论使用上述方法将React React集成到Ember.js应用程序的利弊。
优点
- 逐步迁移ember代码库
- 具有Ember和React组件的单向波
- 易于消耗组件,通过道具传递数据并与修饰语语法共享状态
- 干净而简单的方法
缺点
- 需要每个React组件的Ember包装组件
- 如果更改React组件中的代码,则热模块重新加载将无法工作,因为它是NPM的单独依赖性
- 框架在您的生产捆绑包中额外40 kb(反应运行时)
样品回购
该帖子的代码托管在github here中。非常感谢Edward Faulkner使之成为可能。使用embroider
,还有一种绣花version的version来构建和编译以路线代码拆分的组件。
请看一下GitHub存储库,让我知道您的反馈,在评论部分中查询。如果您觉得这里有更多的利弊,请告诉我们。