gpt4 book ai didi

angular - 将 Angular 应用程序与 ReactJS 应用程序连接起来?

转载 作者:太空狗 更新时间:2023-10-29 17:24:31 25 4
gpt4 key购买 nike

我有一个 Angular 应用程序和我想用 ReactJS 编写的应用程序的某些部分。

如何将 ReactJS 应用程序注入(inject)现有的 Angular 应用程序?我还需要组件的双向通信。

最佳答案

简介:您可以拥有不同的环境、不同的用例和不同的需求。请记住,此解决方案只有一些方法可以触发您发明不同的东西 - 更适合您的用例。
两种不同的解决方案,例如:

  • 没有通信的 Angular-ReactJS
  • 具有双向通信的 Angular-ReactJS

  • 下面的所有代码都是最小的,可以在所呈现的步骤中显示问题。在 GitHub 上,你有一个完整的代码来解决一个问题,与下面的例子并不总是 1:1 的,因为这段代码是扩展的。
    没有通信的 Angular-ReactJS
    要将 ReactJS 应用程序添加到现有的 Angular 应用程序中,您需要安装 5 个 npm 依赖项: react , react-dom :
    npm install --save react
    npm install --save react-dom
    npm install --save-dev @types/react
    npm install --save-dev @types/react-dom
    npm install --save-dev @types/react-select
    下一步 - 我们应该允许使用 jsx模板在 .tsx文件,所以我们应该编辑 tsconfig.json ,并添加:
    {
    ...
    "compilerOptions": {

    "jsx": "react"
    }
    如果您使用 WebStorm,您应该重新启动您的项目,因为 TSLint 在重新启动之前会显示错误。
    为了保持清晰的结构,我创建了以下目录结构:
    angular /
    ng-hero.component.ts // Component in Angular
    react-renderer.component.ts // ReactJS renderer without communication
    react /
    react-application.tsx // React init application
    react-hero.tsx // React hero component
    app.component.html
    app.component.ts
    现在你需要在 Angular 中创建一个特殊的组件,它将负责嵌入 ReactJS 应用程序。这个组件我会叫 ReactRendererComponent .这个组件非常简单,它只有一个模板行,一个带有 import Injector 的构造函数。和一行 ngOnInit :
    @Component({
    selector: 'app-react-renderer',
    template: `<div class="react-container" id="react-renderer"></div>`
    })
    export class ReactRendererComponent implements OnInit {
    constructor(public injector: Injector) { }

    ngOnInit() {
    ReactApplication.initialize('react-renderer', this.injector);
    }
    }
    现在我们需要 ReactApplication我们在其中初始化 ReactJS 应用程序的组件:
    interface IReactApplication {
    injector: Injector;
    }

    class ReactApp extends React.Component<IReactApplication, any> {
    constructor(props) {
    super(props);
    }

    render() {
    return (
    <div className={'renderer'}>
    <h2>ReactJS component: </h2>
    <br/>
    <ReactHero/>
    </div>
    );
    }
    }

    export class ReactApplication {

    static initialize(
    containerId: string,
    injector: Injector
    ) {
    ReactDOM.render(
    <ReactApp injector={injector}/>,
    document.getElementById(containerId)
    );
    }
    }
    我们需要 ReactHero以下示例中使用的组件:
    class ReactHero extends React.Component<any, any> {

    constructor(props) {
    super(props);
    }

    render() {
    return (
    <span>
    <span>react-hero works!</span><br/>
    <span>Don't have any data</span>
    </span>
    );
    }
    }
    export default ReactHero;
    在 Angular App 中,我们应该使用 ReactRenderer组件,所以我们使用:
    App.component data:
    <hr>
    <h2>This is Angular</h2>
    <img width="100" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
    <hr>

    <!-- Without data binding -->
    <app-react-renderer></app-react-renderer>
    此时我们有一个带有嵌入式 ReactJS 应用程序的 Angular 应用程序,但没有任何通信。对你来说够了吗?如果是,那就是全部。如果您需要在两个应用程序之间进行任何类型的通信,我会在下面为您提供 RxJS 选项。
    具有双向通信的 Angular-ReactJS
    在这个例子中,你有 RxJS 支持的双向数据绑定(bind)。您可以获取这些数据,并在您的 ReactJS 应用程序和 Angular 应用程序中使用它们来查看所有更改。这对于很多项目来说已经足够了,但是您可以使用不同的选项来获得这种双向通信,例如,您可以为它们使用 Redux。
    为了清楚起见,下面我为这部分提供了一个完整的目录结构:
    angular /
    hero.service.ts
    ng-hero.component.ts // Component in Angular
    react-bidirectional-renderer.component.ts // ReactJS renderer with bidirectional communication
    model /
    hero.ts // interface for Hero object
    react-bidirectional
    react-bidirectional-application.tsx // React init application with bidirectional communication
    react-bidirectional-hero.tsx // React hero component with RxJS support
    app.component.html
    app.component.ts
    首先,我们创建 IHero数据接口(interface): /model/hero.ts
    export interface IHero {
    name: string;
    age: number;
    }
    在下一步中,我们创建 angular/hero.service.ts服务,在应用程序的 Angular 部分使用它:
    @Injectable({
    providedIn: 'root'
    })
    export class HeroService {
    private heroes$: BehaviorSubject<IHero[]> = new BehaviorSubject([]);

    constructor() {
    }

    addHeroes(hero: IHero) { // To add new hero
    const actualHero = this.heroes$.value;
    actualHero.push(hero);
    this.heroes$.next(actualHero);
    }

    updateHeroAge(heroId: number, age: number) { // To update age of selected hero
    const actualHero = this.heroes$.value;
    actualHero[heroId].age = age;
    this.heroes$.next(actualHero);
    }

    getHeroes$(): BehaviorSubject<IHero[]> { // To get BehaviorSubject and pass it into ReactJS
    return this.heroes$;
    }
    }
    而在 app.component.ts我们用数据(宙斯和波塞冬)初始化:
    @Component({
    selector: 'app-root',
    templateUrl: './app.component.html'
    })
    export class AppComponent implements OnInit {
    public heroesObj$: BehaviorSubject<IHero[]>;
    public heroes: IHero[];

    constructor(private heroService: HeroService) {}

    ngOnInit(): void {
    this.heroService.getHeroes$().subscribe((res: IHero[]) => {
    this.heroes = res;
    });

    this.heroesObj$ = this.heroService.getHeroes$();

    this.initHeroes();
    }

    initHeroes() {
    this.heroService.addHeroes({name: 'Zeus', age: 88});
    this.heroService.addHeroes({name: 'Poseidon', age: 46});
    }
    }
    在下一步中,我们应该准备应用程序的 ReacJS 部分,因此我们创建 react-bidirectional/react-bidirectional-application.tsx文件:
    interface IReactBidirectionalApp {
    injector: Injector;
    heroes$: BehaviorSubject<IHero[]>; // We use this interface to grab RxJS object
    }

    class ReactBidirectionalApp extends React.Component<IReactBidirectionalApp, any> {
    constructor(props) {
    super(props);

    this.state = {
    heroes$: this.props.heroes$ // and we pass this data into ReactBidirectionalHero component
    };
    }

    render() {
    return (
    <div className={'renderer'}>
    <h2>ReactJS component (bidirectional data binding): </h2>
    <ReactBidirectionalHero heroes$={this.state.heroes$}/>
    </div>
    );
    }
    }

    export class ReactBidirectionalApplication {

    static initialize(
    containerId: string,
    injector: Injector,
    heroes$: BehaviorSubject<IHero[]>, // This is necessary to get RxJS object
    ) {
    ReactDOM.render(
    <ReactBidirectionalApp injector={injector} heroes$={heroes$}/>,
    document.getElementById(containerId)
    );
    }
    }
    下一步我们需要 ReactBidirectionalHero组件,所以我们创建它:
    interface IReactBidirectionalHero {
    heroes$: BehaviorSubject<IHero[]>;
    }

    class ReactBidirectionalHero extends React.Component<IReactBidirectionalHero, any> {
    constructor(props) {
    super(props);

    this.state = {
    heroes: []
    };

    this.addAge = this.addAge.bind(this); // Register function to bump age
    this.addHero = this.addHero.bind(this); // Register function to add new Hero
    }

    componentDidMount(): void {
    // In componentDidMount we subscribe heroes$ object
    this.props.heroes$.subscribe((res: IHero[]) => {
    // and we pass this data into React State object
    this.setState({heroes: res});
    });
    }

    addAge(i: number) {
    const temp = this.state.heroes;
    temp[i].age = temp[i].age + 1;

    // In this way we update RxJS object
    this.props.heroes$.next( temp);
    }

    addHero() {
    const temp = this.state.heroes;
    temp.push({name: 'Atena', age: 31});

    // In this way we update RxJS object
    this.props.heroes$.next(temp);
    }

    render() {
    // Hire we render RxJS part of application with addAge button and ADD ATENA button below
    const heroes = this.state.heroes.map((hero: IHero, i) => {
    return <span key={i}>{hero.name} - {hero.age} <button onClick={() => this.addAge(i)}>Add {hero.name} age</button><br/></span>;
    });
    return (
    <span>
    <span>react-hero works!</span><br/>
    {heroes}
    <br/>
    <button onClick={this.addHero}>ADD ATENA</button>
    </span>
    );
    }
    }

    export default ReactBidirectionalHero;
    现在我们需要在 Angular 应用程序中初始化 ReactJS 应用程序,所以我们创建 angular/react-bidirectional-renderer.component.ts - 非常简单,与没有通信的版本相比只有一个变化:
    @Component({
    selector: 'app-react-owc-renderer',
    template: `<div class="react-container" id="react-owc-renderer"></div>`
    })
    export class ReactBidirectionalRendererComponent implements OnInit {
    // Hire we get data from the parent component, but of course, we can also subscribe this data directly from HeroService if we prefer this way
    @Input() heroes$: BehaviorSubject<IHero[]>;

    constructor(public injector: Injector) { }

    ngOnInit() {
    // We add only one parameter into initialize function
    ReactBidirectionalApplication.initialize('react-owc-renderer', this.injector, this.heroes$);
    }
    }
    现在我们应该稍微改变一下 ng-hero.component.ts查看所有效果:
    @Component({
    selector: 'app-ng-hero',
    template: `
    <div>
    <span>ng-hero works!</span><br/>
    <span *ngFor="let hero of heroes; let i = index;">{{hero.name}} - {{hero.age}} - <button (click)="addAge(i)">Add {{hero.name}} age</button><br/></span>
    <br/>
    <button (click)="addHero()">ADD AFRODITA</button>
    </div>
    `
    })
    export class NgHeroComponent implements OnInit {
    public heroes: IHero[];

    constructor(private heroService: HeroService) { }

    ngOnInit() {
    this.heroService.getHeroes$().subscribe((res: IHero[]) => {
    this.heroes = res;
    });
    }

    addAge(heroId: number) {
    this.heroService.updateHeroAge(heroId, this.heroes[heroId].age + 1);
    }

    addHero() {
    this.heroService.addHeroes({name: 'Afrodita', age: 23});
    }

    }
    最后我们改 app.component.html :
    App.component data:
    <hr>
    <h2>This is Angular component: </h2>
    <app-ng-hero></app-ng-hero>
    <hr>

    <!-- With bidirectional data binding-->
    <app-react-owc-renderer [heroes$]="heroesObj$"></app-react-owc-renderer>
    <hr>
    一切都应该有效。如果您有任何问题,请随时提出。
    您可以在 GitHub 上找到此解决方案的完整存储库.
    如果您要查找演示,请单击 hire .
    一些额外的想法
    如您所见,我仅介绍了解决此问题的两种方法。这里只是一些提示,可以为您提供更广阔的视野,并让您有可能为您的用例找到更适合自己的解决方案。
  • 店铺 - 使用 Redux 在 Angular 和 React 应用程序之间共享 Store - 这种方法非常好,因为您不需要关心在组件之间传递数据。这种方法有一些潜在的问题——如果 React 应用程序修改了 store 并且你订阅了这些数据,请记住 NG 更改检测的潜在问题。在某些情况下,在 Angular 应用程序之外修改的数据可能是一个问题,所以请记住这一点。
  • iframe - 这是在没有双向通信的情况下在 Angular 应用程序中执行任何类型的仅使用 ReactJS 组件的最简单方法。您可以只在 URL 的查询参数中传递一些数据并呈现 React 组件。
  • Preact.js - 如果您只想使用一个简单的 React 组件,但又担心包的大小,那么这是一个非常好的方法。 Preact 提供了许多 React 功能,但它非常小,因此您的构建和客户不会对您的技术海市蜃楼产生任何影响。
  • 关于angular - 将 Angular 应用程序与 ReactJS 应用程序连接起来?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54408694/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com