Menggunakan React di aplikasi multi-halaman

122

Saya telah bermain-main dengan React dan sejauh ini saya sangat menyukainya. Saya sedang membangun aplikasi dengan NodeJS dan ingin menggunakan React untuk beberapa komponen interaktif di seluruh aplikasi. Saya tidak ingin menjadikannya aplikasi satu halaman.

Saya belum menemukan apa pun di web yang menjawab pertanyaan-pertanyaan berikut:

Bagaimana cara memecah atau menggabungkan komponen React saya di aplikasi multi-halaman?

Saat ini semua komponen saya ada dalam satu file meskipun saya mungkin tidak pernah memuatnya di beberapa bagian aplikasi.

Sejauh ini saya mencoba menggunakan pernyataan bersyarat untuk membuat komponen dengan mencari ID wadah tempat React akan merender. Saya tidak 100% yakin tentang praktik terbaik dengan React. Ini terlihat seperti ini.

if(document.getElementById('a-compenent-in-page-1')) {
    React.render(
        <AnimalBox url="/api/birds" />,
        document.getElementById('a-compenent-in-page-1')
    );
}

if(document.getElementById('a-compenent-in-page-2')) {
    React.render(
        <AnimalBox url="/api/cats" />,
        document.getElementById('a-compenent-in-page-2')
    );
}

if(document.getElementById('a-compenent-in-page-3')) {
    React.render(
        <AnimalSearchBox url="/api/search/:term" />,
        document.getElementById('a-compenent-in-page-3')
    );
}

Saya masih membaca dokumentasi dan belum menemukan apa yang saya butuhkan untuk aplikasi multi halaman.

Terima kasih sebelumnya.

Jose Carrillo
sumber
coba gunakan plugin requirejs.
amit_183
2
Jika Anda tidak keberatan bahwa ReactJs adalah pustaka JS yang sangat besar yang perlu diinisialisasi untuk setiap halaman (seperti yang Anda katakan Anda tidak membuat aplikasi satu halaman), maka saya tidak yakin itu penting bagi Anda. telah menggabungkan semua komponen menjadi satu file. Ini akan di-cache di klien. Saat halaman dimuat, renderbuatlah komponen yang benar dalam satu scriptblok.
WiredPrairie
Saya mengalami masalah yang sama: Saya memiliki aplikasi yang memuat perpustakaan besar lainnya di halaman yang berbeda, dan saya lebih suka memuat react + satu perpustakaan tergantung pada kebutuhan pengunjung, daripada empat perpustakaan besar untuk berjaga-jaga.
AJFarkas

Jawaban:

83

Saat ini, saya sedang melakukan hal serupa.

Aplikasi ini bukan Aplikasi React lengkap, saya menggunakan React untuk Stuff dinamis, seperti CommentBox, yang autark. Dan dapat dimasukkan di mana saja dengan parameter khusus ..

Namun, semua sub Aplikasi saya dimuat dan dimasukkan ke dalam satu file all.js, sehingga dapat di-cache oleh browser di seluruh halaman.

Saat saya perlu memasukkan Aplikasi ke dalam Template SSR, saya hanya perlu menyertakan DIV dengan kelas "__react-root" dan ID khusus, (nama Aplikasi React yang akan dirender)

Logikanya sangat sederhana:

import CommentBox from './apps/CommentBox';
import OtherApp from './apps/OtherApp';

const APPS = {
  CommentBox,
  OtherApp
};

function renderAppInElement(el) {
  var App = APPS[el.id];
  if (!App) return;

  // get props from elements data attribute, like the post_id
  const props = Object.assign({}, el.dataset);

  ReactDOM.render(<App {...props} />, el);
}

document
  .querySelectorAll('.__react-root')
  .forEach(renderAppInElement)

<div>Some Article</div>
<div id="CommentBox" data-post_id="10" class="__react-root"></div>

<script src="/all.js"></script>

Sunting

Karena webpack sangat mendukung pemisahan kode & LazyLoading, saya pikir masuk akal untuk menyertakan contoh di mana Anda tidak perlu memuat semua aplikasi Anda dalam satu bundel, tetapi membaginya dan memuat sesuai permintaan.

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

const apps = {
  'One': () => import('./One'),
  'Two': () => import('./Two'),
}

const renderAppInElement = (el) => {
  if (apps[el.id])  {
    apps[el.id]().then((App) => {
      ReactDOM.render(<App {...el.dataset} />, el);
    });
  }
}
webdeb
sumber
1
Tampak hebat, adakah yang menjalankan ini saat menggunakan npm create-react-app? Menurut saya ini tidak akan berhasil untuk saya ... Saya baru saja menjalankannya dengan 1 aplikasi dan dapat melihat cara kerjanya, tetapi versi saya tidak akan membuat build produksi yang berfungsi dengan benar.
Sprose
@Sprose juga harus berfungsi dengan create-react-app, apakah saya melewatkan sesuatu? Mungkin Anda dapat membagikan contoh kecil di github yang tidak memilikinya, saya tidak melihat alasan mengapa tidak boleh
webdeb
1
@Sprose minta jawaban yang terlambat, tetapi saya pikir Anda mencoba sesuatu yang sama sekali berbeda, apa yang coba dipecahkan oleh pendekatan ini. IMO create react appmemberi Anda beberapa perkakas mudah untuk dibuat bundle.js. Jadi, tujuan dari jawaban saya adalah untuk menggunakan yang sama bundle.jsdan menggunakannya di berbagai situs SSR mutliple, dan memuat banyak aplikasi React yang berbeda ke dalam satu halaman. Maaf, jika jawaban saya tidak sesuai dengan kebutuhan Anda, silakan buat Posting baru dan jelaskan apa yang Anda coba lakukan, saya akan mencoba membantu Anda.
webdeb
1
@SorcererApprentice cra menggunakan webpack, Anda harus mengeluarkan dan kemudian memeriksa dasar-dasarnya webpack.js.org/guides/getting-started/#creating-a-bundle
webdeb
1
@SorcererApprentice pada dasarnya seseorang memposting konfigurasi webpack di halaman ini: stackoverflow.com/a/41857199/5004923
webdeb
52

Anda dapat memberikan beberapa titik masuk untuk aplikasi di file webpack.config.js:

var config = {
  entry: {
    home: path.resolve(__dirname, './src/main'),
    page1: path.resolve(__dirname, './src/page1'),
    page2: path.resolve(__dirname, './src/page2'),
    vendors: ['react']
  },
 output: {
    path: path.join(__dirname, 'js'),
    filename: '[name].bundle.js',
    chunkFilename: '[id].chunk.js'
  },
}

maka Anda dapat memiliki di folder src Anda tiga file html berbeda dengan file js masing-masing (contoh untuk halaman1):

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Page 1</title>
</head>
<body>
  <div id="app"></div>
  <script src="./vendors.js"></script>
  <script src="./page1.bundle.js"></script>
</body>
</html>

File JavaScript:

import React from 'react'
import ReactDom from 'react-dom'
import App from './components/App'
import ComponentA from './components/ReactComponentA'
ReactDom.render(<div>
                  <App title='page1' />
                  <ReactComponentA/>
                 </div>, document.getElementById('app'))

Komponen React yang berbeda kemudian dapat dimuat untuk setiap halaman.

Cocomico
sumber
1
Saya membaca tentang di bawah ini di halaman webex. webpack version < 4 it was common to add vendors as separate entrypoint to compile it as separate file (in combination with the CommonsChunkPlugin). This is discouraged in webpack 4. Instead the optimization.splitChunks option takes care of separating vendors and app modules and creating a separate file. Do not create a entry for vendors or other stuff which is not the starting point of execution.Jadi, apakah sampel ini harus diperbarui untuk webpack 4+?
Ramesh
32

Saya membangun aplikasi dari nol dan belajar sambil jalan, tapi saya rasa yang Anda cari adalah React-Router . React-Router memetakan komponen Anda ke URL tertentu. Sebagai contoh:

render((
    <Router>
        <Route path="/" component={App}>
            <Route path="api/animals" component={Animals}>
               <Route path="birds" component={Birds}/>
               <Route path="cats" component={Cats}/>
            </Route>
        </Route>
        <Route path="api/search:term" component={AnimalSearchBox}>
    </Router>
), document.body)

Dalam kasus pencarian, 'term' dapat diakses sebagai properti di AnimalSearchBox:

componentDidMount() {
    // from the path `/api/search/:term`
    const term = this.props.params.term
}

Cobalah. Tutorial ini adalah salah satu yang menempatkan saya di atas dalam hal pemahaman saya tentang ini dan topik terkait lainnya.


Berikut jawaban asli:

Saya menemukan jalan saya di sini mencari jawaban yang sama. Lihat apakah posting ini menginspirasi Anda. Jika aplikasi Anda seperti milik saya, itu akan memiliki area yang sangat sedikit berubah dan hanya bervariasi di bagian utama. Anda dapat membuat widget yang tanggung jawabnya untuk membuat widget berbeda berdasarkan status aplikasi. Dengan menggunakan arsitektur flux, Anda dapat mengirimkan tindakan navigasi yang mengubah status widget body Anda, yang secara efektif memperbarui body halaman saja.

Itulah pendekatan yang saya coba sekarang.

Scott
sumber
8
Bagaimana jika jalur URL dibuat oleh kode backend saya (nodejs dalam kasus ini)? Akankah Routerbekerja dengan cara yang sama dalam satu aplikasi halaman?
Jose Carrillo
1
@Scott Bagaimana jika saya tidak ingin mengekspos fungsionalitas halaman admin yang memiliki widget khusus? Menggunakan react dimungkinkan untuk membuat ulang tampilan dan nuansa tanpa otentikasi nyata.
Kairat Kempirbaev
11

Apakah Anda menggunakan CMS? Mereka cenderung suka mengubah url yang dapat merusak aplikasi Anda.

Cara lain adalah menggunakan sesuatu seperti React Habitat .

Dengan itu, Anda dapat mendaftarkan komponen dan mereka secara otomatis terekspos ke dom.

Contoh

Daftarkan komponen:

container.register('AnimalBox', AnimalBox);
container.register('AnimalSearchBox', AnimalSearchBox);

Kemudian mereka tersedia di dom Anda seperti ini:

<div data-component="AnimalBox"></div>

<div data-component="AnimalSearchBox"></div>

Di atas akan otomatis diganti dengan komponen react Anda.

Anda kemudian dapat secara otomatis meneruskan properti (atau props) ke komponen Anda juga:

<div data-component="AnimalBox" data-prop-size="small"></div>

Ini akan terlihat sizesebagai penyangga komponen Anda. Ada opsi tambahan untuk meneruskan tipe lain seperti json, array's, ints, floats dll.

jennas
sumber
2

Saya tahu sudah lama sejak pertanyaan ini diajukan, tetapi semoga ini membantu seseorang.

Seperti yang disebutkan @Cocomico, Anda dapat memberikan beberapa titik masuk untuk aplikasi di file webpack.config.js. Jika Anda mencari pengaturan Webpack sederhana (berdasarkan gagasan beberapa titik masuk) yang memungkinkan Anda menambahkan komponen React ke halaman statis, Anda dapat mempertimbangkan untuk menggunakan ini: https://github.com/przemek-nowicki/multi-page -app-dengan-bereaksi

Przemek Nowicki
sumber
-1

Saya sarankan Anda melihat InertiaJS: https://inertiajs.com/

Dengan Inersia, Anda membangun aplikasi seperti yang selalu Anda lakukan dengan kerangka kerja web sisi server pilihan Anda. Anda menggunakan fungsionalitas framework yang ada untuk perutean, pengontrol, middleware, autentikasi, otorisasi, pengambilan data, dan lainnya.

Satu-satunya hal yang berbeda adalah lapisan tampilan Anda. Alih-alih menggunakan rendering sisi server (misalnya template Blade atau ERB), tampilannya adalah komponen halaman JavaScript. Ini memungkinkan Anda untuk membangun seluruh front-end Anda menggunakan React, Vue atau Svelte.

Agu Dondo
sumber