将Angular应用程序与ReactJS应用程序连接? [英] Connect Angular application with ReactJS app?

查看:62
本文介绍了将Angular应用程序与ReactJS应用程序连接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a Angular app and some part of application I want write in ReactJS.

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

How can I inject ReactJS app into existing Angular application? I need also bidirectional communication for components.

推荐答案

您可能需要其他选项,因此我将其写在第二段中:

  • 无需通信的Angular-ReactJS
  • 具有双向通信的Angular-ReactJS
  • 下面的所有代码都很少显示出所提出步骤中的问题.在GitHub上,您拥有完整的代码来解决问题,下面的示例并不总是1:1,因为此代码已扩展.

    All code below is minimal to show a problem on a presented step. On GitHub you have a complete code to solve a problem, not always 1:1 with example below because this code is extended.

    要将ReactJS应用添加到现有的Angular应用中,您需要安装5个npm依赖项:reactreact-dom:

    To add ReactJS app into existing Angular application you need to install 5 npm dependencies: 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
    

    下一步-我们应该允许在.tsx文件中使用jsx模板,因此我们应该编辑tsconfig.json,并添加:

    Next step - we should permit to use jsx template in .tsx files, so we should edit tsconfig.json, and add:

    {
        ...
       "compilerOptions": {
        …
        "jsx": "react"
    }
    

    如果使用WebStorm,则应重新启动项目,因为tslint会显示错误,直到重新启动为止.

    If you use WebStorm you should restart your project because tslint show error till restart.

    为了保持清晰的结构,我创建了以下目录结构:

    To keep clear structure, I create this structure of directory:

    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中的一行:

    Now you need create special component in Angular, which will be responsible for embedding ReactJS application. This component I will call ReactRendererComponent. This component is very simple and it have only one template line, constructor with import Injector and one line in 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应用:

    Now we need ReactApplication component where we initialize ReactJS app:

    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组件:

    And we need ReactHero component which was used in example below:

    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组件,所以我们使用:

    In Angular App we should use ReactRenderer component, so we use:

    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>
    

    目前,我们有Angular应用程序和嵌入式ReactJS应用程序,但没有任何通信.对您来说足够了吗?如果是的话,就这些了.如果您需要在两个应用程序之间进行任何形式的通信,请在下面为您介绍RxJS选项.

    At this moment we have Angular app with embedded ReactJS app, but without any communication. Is it enough for you? If yes, it's all. If you need any kind of communication between both application, I present you RxJS option below.

    在此示例中,RxJS支持双向数据绑定.您可以获取此数据,并在ReactJS应用和Angular应用中使用它们以查看所有更改.对于许多项目来说,这已经足够了,但是您可以使用不同的选项来获得这种双向通信,例如,可以对它们使用Redux.

    In this example you have bidirectional databinding supported by RxJS. You can get this data, and use them in your ReactJS app and Angular app see all changes. This is enough for a lot of projects, but you can use different option to get this bidirectional communication, for example you can use Redux for them.

    为清楚起见,下面我将提供此部分的完整目录结构:

    To keep it clear, below I present complete directory structure for this part:

    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接口:/model/hero.ts

    First of all we create IHero interface with data: /model/hero.ts

    export interface IHero {
      name: string;
      age: number;
    }
    

    下一步,我们创建angular/hero.service.ts服务,以在应用程序的Angular部分中使用它:

    In next step we create angular/hero.service.ts service, to use it in Angular part of application:

    @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中,我们使用数据(Zeus和Poseidon)进行初始化:

    And in app.component.ts we initialize with data (Zeus and Poseidon):

    @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文件:

    In next step we should prepare ReacJS part of application, so we create react-bidirectional/react-bidirectional-application.tsx file:

    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组件,因此我们将其创建:

    In next step we need ReactBidirectionalHero component, so we create it:

    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-非常简单,与版本相比,只有一个更改而没有通信:

    Now we need to initialize ReactJS app in Angular application, so we create angular/react-bidirectional-renderer.component.ts - it's very simple, with only one changes in compare to version without communication:

    @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 parent component, but of course we can also subscribe this data directly form 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才能看到所有效果:

    And now we should change a little ng-hero.component.ts to see all efect:

    @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>
    

    一切都应该正常进行.如果您有任何问题,请随时提问.

    And everything should work. If you have any problem, feel free to ask.

    使用此解决方案的完整存储库,您可以在 GitHub 上找到.

    Complete repository with this solution you can find on GitHub.

    如果要查找演示,请单击租用.

    If you look for demo, click hire.

    这篇关于将Angular应用程序与ReactJS应用程序连接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆