angular reactjs

¿Conecta la aplicación Angular con la aplicación ReactJS?



(1)

Tengo una aplicación Angular y parte de la aplicación que quiero escribir en ReactJS.

¿Cómo puedo inyectar la aplicación ReactJS en la aplicación Angular existente? Necesito también comunicación bidireccional para componentes.


Puedes necesitar una opción diferente, así que la escribo en 2 párrafos:

  • Angular-ReactJS sin comunicación
  • Angular-ReactJS con comunicación bidireccional.

Todo el código a continuación es mínimo para mostrar un problema en un paso presentado. En GitHub usted tiene un código completo para resolver un problema, no siempre 1: 1 con el siguiente ejemplo porque este código está extendido.

Angular-ReactJS sin comunicación

Para agregar la aplicación ReactJS a la aplicación Angular existente, necesita instalar dependencias de 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

Paso siguiente: debemos permitir el uso de la plantilla jsx en los archivos .tsx , por lo que deberíamos editar tsconfig.json y agregar:

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

Si usa WebStorm, debe reiniciar su proyecto porque tslint muestra un error hasta que se reinicia.

Para mantener una estructura clara, creo esta estructura de directorio:

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

Ahora necesita crear un componente especial en Angular, que será responsable de integrar la aplicación ReactJS. Este componente lo llamaré ReactRendererComponent . Este componente es muy simple y solo tiene una línea de plantilla, un constructor con un import Injector y una línea en 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); } }

Ahora necesitamos el componente ReactApplication donde inicializamos la aplicación 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) ); } }

Y necesitamos el componente ReactHero que se usó en el siguiente ejemplo:

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;

En la aplicación Angular debemos usar el componente ReactRenderer , así que usamos:

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>

En este momento tenemos la aplicación Angular con la aplicación ReactJS incorporada, pero sin ninguna comunicación. ¿Es suficiente para usted? Si es así, es todo. Si necesita algún tipo de comunicación entre ambas aplicaciones, a continuación le presento la opción RxJS.

Angular-ReactJS con comunicación bidireccional.

En este ejemplo, tiene un enlace de datos bidireccional soportado por RxJS. Puede obtener estos datos y utilizarlos en su aplicación ReactJS y la aplicación Angular para ver todos los cambios. Esto es suficiente para muchos proyectos, pero puede usar diferentes opciones para obtener esta comunicación bidireccional, por ejemplo, puede usar Redux para ellos.

Para que quede claro, a continuación presento la estructura completa del directorio para esta parte:

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

En primer lugar, creamos IHero interfaz IHero con datos: /model/hero.ts

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

En el siguiente paso creamos el servicio angular/hero.service.ts , para usarlo en la parte angular de la aplicación:

@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$; } }

Y en app.component.ts inicializamos con datos (Zeus y 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}); } }

En el siguiente paso, debemos preparar la parte de la aplicación ReacJS, por lo que creamos el archivo 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) ); } }

En el siguiente paso, necesitamos el componente ReactBidirectionalHero , así que lo creamos:

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;

Ahora necesitamos inicializar la aplicación ReactJS en la aplicación Angular, así que creamos angular/react-bidirectional-renderer.component.ts - es muy simple, con solo un cambio en comparación con la versión sin comunicación:

@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$); } }

Y ahora deberíamos cambiar un poco ng-hero.component.ts para ver todos los efectos:

@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}); } }

Finalmente cambiamos 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>

Y todo debería funcionar. Si tiene algún problema, no dude en preguntar.

Completa el repositorio con esta solución que puedes encontrar en GitHub .

Si buscas demo, haz clic en hire .