Saya punya masalah. Aplikasi ini ditulis dalam Angular, dan pustaka komponen di Bereaksi. Mengkloning perpustakaan terlalu mahal. Jadi, Anda perlu menggunakan komponen Bereaksi dalam aplikasi Angular dengan biaya minimal. Kami mencari cara untuk melakukannya.
Penafian
Saya bukan spesialis di Angular sama sekali. Saya mencoba versi pertama pada tahun 2017, kemudian melihat sedikit pada AngularDart, dan sekarang saya telah menemukan dukungan aplikasi pada versi modern dari framework. Jika Anda merasa bahwa keputusan itu aneh atau "dari dunia lain", itu tampaknya tidak bagi Anda.
Solusi yang disajikan dalam artikel ini belum diuji dalam proyek nyata dan hanya konsep. Gunakan dengan risiko Anda sendiri.
Masalah
Saya sekarang mendukung dan mengembangkan aplikasi yang cukup besar pada Angular 8. Plus, ada beberapa aplikasi kecil di Bereaksi dan berencana untuk membangun selusin lebih (juga di Bereaksi). Semua aplikasi digunakan untuk kebutuhan internal perusahaan dan harus dalam gaya yang sama. Satu-satunya cara logis adalah membuat pustaka komponen dengan dasar di mana Anda dapat dengan cepat membangun aplikasi apa pun.
Tetapi dalam situasi saat ini, Anda tidak bisa hanya mengambil dan menulis perpustakaan di Bereaksi. Anda tidak dapat menggunakannya dalam aplikasi terbesar - ini ditulis dalam Angular. Saya bukan orang pertama yang menghadapi masalah ini. Hal pertama yang ada di Google untuk "bereaksi dalam sudut" adalah repositori Microsoft . Sayangnya, solusi ini tidak memiliki dokumentasi sama sekali. Plus, dalam readme proyek itu jelas dikatakan bahwa paket tersebut digunakan secara internal oleh Microsoft, tim tidak memiliki rencana yang jelas untuk pengembangannya dan hanya risiko Anda sendiri untuk menggunakannya. Saya belum siap untuk menyeret paket ambigu ke dalam produksi, jadi saya memutuskan untuk menulis sepeda

Situs resmi @ angular-react / core
Solusi
Bereaksi adalah perpustakaan yang dirancang untuk memecahkan satu masalah khusus - mengelola pohon DOM dokumen. Kita bisa meletakkan elemen Bereaksi apa pun di simpul DOM yang arbitrer.
const Hello = () => <p>Hello, React!</p>; render(<Hello />, document.getElementById('#hello'));
Selain itu, tidak ada batasan pada panggilan berulang ke fungsi render
. Artinya, dimungkinkan untuk membuat setiap komponen secara terpisah di DOM. Dan inilah yang akan membantu mengambil langkah pertama dalam integrasi.
Persiapan
Pertama-tama, penting untuk dipahami bahwa Bereaksi secara default tidak memerlukan kondisi khusus selama perakitan. Jika Anda tidak menggunakan JSX, tetapi membatasi createElement
untuk memanggil createElement
, maka Anda tidak perlu mengambil langkah apa pun, semuanya hanya akan berjalan di luar kotak.
Tapi, tentu saja, kita terbiasa menggunakan JSX dan tidak mau kehilangan itu. Untungnya, Angular menggunakan TypeScript secara default, yang dapat mengubah JSX menjadi panggilan fungsi. Anda hanya perlu menambahkan flag compiler --jsx=react
atau di tsconfig.json
di bagian compilerOptions
tambahkan baris "jsx": "react"
.
Integrasi Tampilan
Untuk memulai, kita perlu memastikan bahwa komponen Bereaksi ditampilkan di dalam aplikasi Angular. Yaitu, sehingga elemen DOM yang dihasilkan dari pekerjaan perpustakaan mengambil tempat yang tepat di pohon elemen.
Setiap kali Anda menggunakan komponen Bereaksi, berpikir untuk memanggil fungsi render
dengan benar terlalu sulit. Plus, di masa depan kita perlu mengintegrasikan komponen di tingkat data dan pengendali acara. Dalam hal ini, masuk akal untuk membuat komponen Angular yang akan merangkum seluruh logika membuat dan mengendalikan elemen Bereaksi.
Kode komponen Angular sangat sederhana. Itu sendiri hanya membuat wadah kosong dan mendapat tautan ke sana. Dalam hal ini, pada saat inisialisasi, render dari elemen React disebut. Itu dibuat menggunakan fungsi createElement
dan diteruskan ke fungsi render
, yang menempatkannya di simpul DOM yang dibuat dari Angular. Anda dapat menggunakan komponen seperti itu seperti komponen Angulat lainnya, tanpa syarat khusus.
Integrasi Input
Biasanya, saat menampilkan elemen antarmuka, Anda perlu mentransfer data kepada mereka. Semuanya di sini juga cukup membosankan - saat memanggil createElement
Anda dapat meneruskan data apa pun melalui alat peraga ke komponen.
Sekarang Anda dapat meneruskan string name
ke komponen Angular, itu akan jatuh ke komponen Bereaksi dan akan diberikan. Tetapi jika garis berubah karena beberapa alasan eksternal, Bereaksi tidak akan mengetahuinya dan kami akan mendapatkan tampilan yang ketinggalan zaman. Angular memiliki ngOnChanges
siklus hidup ngOnChanges
yang memungkinkan Anda untuk melacak perubahan dalam parameter komponen dan reaksi terhadapnya. Kami mengimplementasikan antarmuka OnChanges
dan menambahkan metode:
Cukup memanggil fungsi render
lagi dengan elemen yang dibuat dari properti baru, dan perpustakaan itu sendiri akan mencari tahu bagian mana dari pohon yang harus dirender. Status lokal di dalam komponen juga akan dipertahankan.
Setelah manipulasi ini, komponen Sudut dapat digunakan dengan cara biasa dan meneruskan data ke sana.
<app-hello name="Angular"></app-hello> <app-hello [name]="name"></app-hello>
Untuk pekerjaan yang lebih baik dengan memperbarui komponen, Anda dapat melihat ke arah strategi deteksi perubahan . Saya tidak akan mempertimbangkan ini secara rinci.
Integrasi Output
Masalah lain tetap - reaksi aplikasi terhadap peristiwa di dalam komponen-React. Mari kita @Output
dekorator @Output
dan meneruskan panggilan balik ke komponen melalui alat peraga.
Selesai Saat menggunakan komponen, Anda dapat mendaftarkan penangan acara dan meresponsnya.
<app-hello [name]="name" (click)="sayHello($event)"></app-hello>
Hasilnya adalah pembungkus yang berfungsi penuh untuk komponen Bereaksi untuk digunakan di dalam aplikasi Angular. Itu dapat mengirimkan data dan menanggapi peristiwa di dalamnya.
Satu hal lagi ...
Bagi saya, hal yang paling nyaman di Angular adalah Pengikatan Data Dua ngModel
, ngModel
. Lebih mudah, sederhana, hanya membutuhkan sedikit kode. Namun dalam implementasi saat ini, integrasi tidak dimungkinkan. Ini bisa diperbaiki. Sejujurnya, saya tidak begitu mengerti bagaimana mekanisme ini bekerja dari sudut pandang perangkat internal. Oleh karena itu, saya akui bahwa solusi saya super-suboptimal dan saya akan senang jika Anda menulis di komentar cara yang lebih indah untuk mendukung ngModel
.
Pertama-tama, Anda perlu mengimplementasikan antarmuka ControlValueAccessor
(dari paket @angular/forms
dan menambahkan penyedia baru ke komponen.
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'; const REACT_VALUE_ACCESSOR: any = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => HelloComponent), multi: true }; @Component({ selector: 'app-hello', template: `<div #react></div>`, providers: [PREACT_VALUE_ACCESSOR], }) export class PreactComponent implements OnInit, OnChanges, ControlValueAccessor {
Antarmuka ini membutuhkan implementasi metode onBlur
, writeValue
, registerOnChange
, registerOnTouched
. Semuanya dijelaskan dengan baik dalam dokumentasi. Kami menyadarinya.
Setelah itu, Anda perlu memastikan bahwa semua ini diteruskan ke komponen Bereaksi. Sayangnya, Bereaksi tidak dapat bekerja dengan Pengikatan Data Dua Arah, jadi kami akan memberinya nilai dan panggilan balik untuk mengubahnya. renderReactElement
metode renderReactElement
.
Dan dalam komponen Bereaksi, kita akan menggunakan nilai ini dan panggilan balik.
export const Hello = ({ name, onClick, model }) => ( <div> <p>Hello, {name}!</p> <button onClick={onClick}>Say "hello"</button> <input value={model.value} onChange={e => model.onChange(e.target.value)} /> </div> );
Sekarang, kami benar-benar mengintegrasikan Bereaksi ke Angular. Anda dapat menggunakan komponen yang dihasilkan sesuka Anda.
<app-hello [name]="name" (click)="sayHello($event)" [(ngModel)]="name" ></app-hello>
Ringkasan
React adalah perpustakaan yang sangat sederhana yang mudah diintegrasikan dengan apa pun. Dengan menggunakan pendekatan yang ditunjukkan, Anda tidak hanya dapat menggunakan komponen Bereaksi apa pun di dalam aplikasi Angular secara berkelanjutan, tetapi juga secara bertahap memigrasikan seluruh aplikasi.
Pada artikel ini, saya tidak menyentuh masalah styling sama sekali. Jika Anda menggunakan solusi CSS-in-JS klasik (komponen gaya, emosi, JSS), Anda tidak perlu mengambil tindakan tambahan apa pun. Tetapi jika proyek membutuhkan solusi yang lebih produktif (astroturf, linaria, Modul CSS), Anda harus bekerja pada konfigurasi webpack. Cerita fitur - Sesuaikan Konfigurasi Webpack di Aplikasi Sudut Anda .
Untuk memigrasikan aplikasi sepenuhnya dari Angular ke React, Anda masih perlu menyelesaikan masalah penerapan layanan dalam komponen React. Cara sederhana adalah dengan mendapatkan layanan dalam komponen pembungkus dan menyebarkannya melalui alat peraga. Cara yang sulit adalah menulis layer yang akan mendapatkan layanan dari injektor dengan token. Pertimbangan masalah ini di luar cakupan artikel.
Bonus
Penting untuk dipahami bahwa dengan pendekatan ini ke 85KB Angular, hampir 40KB kode react
dan react-dom
react
. Ini dapat memiliki dampak signifikan pada kecepatan aplikasi. Saya sarankan mempertimbangkan menggunakan miniatur Preact, yang beratnya hanya 3KB. Integrasi hampir tidak berbeda.
- Di
tsconfig.json
menambahkan opsi kompilasi baru - "jsxFactory": "h"
, ini akan menunjukkan bahwa Anda perlu menggunakan fungsi h
untuk mengkonversi JSX. Sekarang, di setiap file dengan kode JSX - import { h } from 'preact'
. - Semua panggilan ke
React.createElement
digantikan oleh Preact.h
. - Semua panggilan ke
ReactDOM.render
digantikan oleh Preact.render
.
Selesai! Baca instruksi untuk bermigrasi dari React ke Preact . Praktis tidak ada perbedaan.
UPD 19.9.19 16.49
Tematik tautan dari komentar - Micro Frontends
UPD 20.9.19 14.30
Link tematis lain dari komentar - Micro Frontends