React Component を wrap する Angular component を作成する

2021/05/08

Angular

React.js

はじめに

UIだけでもReactで書いておけばNext.jsに移行するとき楽なんじゃないかなという妄想から始めた。 Angularライブラリの恩恵を受けつつReactを使えるのでわりといい気がする。

AngularCompoentでReactをwrapする

プロジェクトにReactを追加する。

npm install --save react react-dom
npm install --save-dev @types/react @types/react-dom

# お好みで
npm install --save styled-components
npm install --save-dev @types/styled-components

moduleとcomponentを作成する。

npx ng g module ui/react-wrapper
npx ng g component ui/react-wrapper/react-wrapper

moduleexport でcomponentがimport先で使えるように設定する

@NgModule({
  ...
  exports: [
    ReactWrapperComponent
  ],
})
export class ReactWrapperModule { }

一旦 stateprop を忘れてとりあえずレンダリングされるwrapper compoentを実装する。

import { Component, OnInit, AfterViewInit, OnDestroy, Input, ElementRef } from '@angular/core';

import * as React from 'react';
import * as ReactDOM from 'react-dom';

@Component({
  selector: 'react-wrapper',
  template: ''
})
export class ReactWrapperComponent implements OnInit, AfterViewInit, OnDestroy {
  @Input() reactCompoent:React.Component | any;

  constructor(
    private elementRef:ElementRef
  ) { }

  ngOnInit(): void {
  }

  ngAfterViewInit(): void {
    ReactDOM.render(
      React.createElement(this.reactCompoent),
      this.elementRef.nativeElement
    )
  }

  ngOnDestroy(): void {
    ReactDOM.unmountComponentAtNode(
      this.elementRef.nativeElement
    );
  }

}

使用例

npx ng g module ui/react-card
npx ng g component ui/react-card/react-card
mkdir src/app/ui/react-card/reaat-item
touch src/app/ui/react-card/reaat-item/react-card.tsx

*.tsx ファイルを import できるように tsconfig.app.json を変更。

{
  ...
  "include": [
    "src/**/*.d.ts"
    "src/**/*.tsx"
  ],
  ...
}

tsconfig.json に以下を追加。

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

react-card.module で先程作成したWrapper Componentをimportする。

import { ReactWrapperModule } from '../react-wrapper/react-wrapper.module'

@NgModule({
  ...
  imports: [
    ...
    ReactWrapperModule
  ],
  ...
  exports: [
    ReactCardComponent
  ],
})
export class ReactCardModule { }

適当にReact Componentを作成。

import * as React from 'react';
import styled from 'styled-components';

type prop = {}

const Wrapper = styled.div`
  padding: var(--size-itemInnerPadding);
  background-color: var(--color-Main);
  border: 3px solid var(--color-Paragraph);
  border-radius: var(--size-cardBorder);
`

export const RCComponent:React.FC<prop> = prop => {
  return (
    <Wrapper>
      sample text.
    </Wrapper>
  );
}

compoent側でtsxを読み込み、Wrapper Componentに渡す。

<react-wrapper
  [reactCompoent]="reactCompoent"
>
</react-wrapper>
import { RCComponent } from '../reaat-item/react-card';

@Component({
  selector: 'react-card',
  templateUrl: './react-card.component.html',
  styleUrls: ['./react-card.component.scss']
})
export class ReactCardComponent implements OnInit {
  reactCompoent = RCComponent;
  ...
}

所感

  • ui コンポーネントをReactで書くことができるので柔軟な開発環境を構築できるのではないかと
    • ここまでやるならAngularですべて完結したほうが良い
  • propstate 対応をそのうちする。
    • 当ブログで使用してるComponentをとりあえずReactに置き換えてみる。