Utilizzo di React in un'app multipagina


122

Ho giocato con React e finora mi piace molto. Sto creando un'app con NodeJS e vorrei utilizzare React per alcuni dei componenti interattivi dell'applicazione. Non voglio renderlo un'app a pagina singola.

Non ho ancora trovato nulla sul web che risponda alle seguenti domande:

Come posso suddividere o raggruppare i miei componenti React su un'app multipagina?

Attualmente tutti i miei componenti sono in un file anche se potrei non caricarli mai in alcune sezioni dell'app.

Finora sto provando a utilizzare istruzioni condizionali per rendere i componenti cercando l'ID del contenitore in cui React renderà. Non sono sicuro al 100% di quali siano le migliori pratiche con React. Sembra qualcosa di simile.

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

Sto ancora leggendo la documentazione e non ho ancora trovato quello che mi serve per un'app multipagina.

Grazie in anticipo.


prova a usare il plugin requirejs.
amit_183

2
Se non ti dispiace che ReactJs sia una libreria JS molto grande che dovrà essere inizializzata per ogni pagina (come hai detto che non stai creando un'app a pagina singola), allora non sono sicuro che sia importante che tu ' ho combinato tutti i componenti in un unico file. Verrà memorizzato nella cache del client. Quando una pagina viene caricata, renderimpostala come componente corretto in un scriptblocco.
WiredPrairie

Sto riscontrando lo stesso problema: ho un'app che carica altre librerie di grandi dimensioni su pagine diverse e preferisco caricare solo react + una libreria a seconda delle esigenze del visitatore, piuttosto che quattro grandi librerie per ogni evenienza.
AJFarkas

Risposte:


83

Attualmente sto facendo qualcosa di simile.

L'applicazione non è un'app React completa, sto usando React per cose dinamiche, come CommentBox, che è autark. E può essere incluso in qualsiasi punto con parametri speciali ..

Tuttavia, tutte le mie app secondarie vengono caricate e incluse in un unico file all.js, quindi possono essere memorizzate nella cache dal browser tra le pagine.

Quando devo includere un'app nei modelli SSR, devo solo includere un DIV con la classe "__react-root" e un ID speciale, (il nome dell'app React da renderizzare)

La logica è davvero semplice:

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>

modificare

Poiché webpack supporta perfettamente la suddivisione del codice e il LazyLoading, ho pensato che avesse senso includere un esempio in cui non è necessario caricare tutte le app in un unico pacchetto, ma suddividerle e caricarle su richiesta.

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

1
Sembra fantastico, qualcuno lo ha eseguito quando si utilizza npm create-react-app? Non penso che questo funzionerebbe per me ... L'ho in esecuzione con l'app 1 solo ora e posso vedere come potrebbe funzionare ma la mia build non creerà una build di produzione che funzioni correttamente.
Sprose

@Sprose dovrebbe funzionare anche con create-react-app, mi manca qualcosa? Forse puoi condividere un piccolo esempio su GitHub dove non lo fa, non vedo un motivo per cui non dovrebbe
webdeb

1
@Sprose cerca la risposta tardiva, ma penso che tu stia provando qualcosa di completamente diverso, ciò che questo approccio cerca di risolvere. IMO create react appti offre alcuni strumenti facili da creare bundle.js. Quindi, lo scopo della mia risposta è usare lo stesso bundle.jse usarlo su più siti SSR e caricare molte diverse applicazioni React in una singola pagina. Scusa, se la mia risposta non si adatta alle tue esigenze, sentiti libero di creare un nuovo Post e descrivi cosa stai cercando di fare, proverei ad aiutarti.
webdeb

1
@SorcererApprentice cra usa webpack, devi espellere e poi controllare le basi webpack.js.org/guides/getting-started/#creating-a-bundle
webdeb

1
@SorcererApprentice fondamentalmente qualcuno ha postato la configurazione webpack in questa pagina: stackoverflow.com/a/41857199/5004923
webdeb

52

È possibile fornire diversi punti di ingresso per l'applicazione nel 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'
  },
}

quindi puoi avere nella tua cartella src tre diversi file html con i rispettivi file js (esempio per page1):

<!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'))

È quindi possibile caricare diversi componenti React per ogni singola pagina.


1
Ho letto di seguito nella pagina 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.Quindi, questo esempio dovrebbe essere aggiornato per webpack 4+?
Ramesh

32

Sto costruendo un'applicazione da zero e sto imparando mentre vado, ma penso che quello che stai cercando sia React-Router . React-Router mappa i tuoi componenti a URL specifici. Per esempio:

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)

Nel caso di ricerca, "termine" è accessibile come una proprietà in AnimalSearchBox:

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

Provalo. Questo tutorial è quello che mi ha messo in cima in termini di comprensione di questo e di altri argomenti correlati.


Segue la risposta originale:

Ho trovato la mia strada qui cercando la stessa risposta. Vedi se questo post ti ispira. Se la tua applicazione è qualcosa di simile alla mia, avrà aree che cambiano molto poco e variano solo nel corpo principale. È possibile creare un widget la cui responsabilità è di rendere un widget diverso in base allo stato dell'applicazione. Utilizzando un'architettura di flusso, è possibile inviare un'azione di navigazione che cambia lo stato in cui passa il widget del corpo, aggiornando efficacemente solo il corpo della pagina.

Questo è l'approccio che sto tentando ora.


8
Cosa succede se il percorso dell'URL viene creato dal mio codice di backend (nodejs in questo caso)? Funzionerà allo Routerstesso modo in un'app a pagina singola?
Jose Carrillo

1
@Scott E se non volessi esporre la funzionalità della pagina di amministrazione che ha widget speciali? Utilizzando React è possibile ricreare l'aspetto grafico senza una vera autenticazione.
Kairat Kempirbaev

11

Stai usando un CMS? A loro piace cambiare gli URL che potrebbero interrompere la tua applicazione.

Un altro modo è usare qualcosa come React Habitat .

Con esso, puoi registrare i componenti e questi vengono automaticamente esposti al dom.

Esempio

Registra componente (i):

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

Quindi sono disponibili nel tuo dominio in questo modo:

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

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

Quanto sopra verrà automaticamente sostituito con i tuoi componenti reattivi.

Puoi quindi passare automaticamente proprietà (o oggetti di scena) anche ai tuoi componenti:

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

Questo esporrà sizecome un sostegno al tuo componente. Ci sono opzioni aggiuntive per passare altri tipi come json, array's, ints, float ecc.


2

So che è passato un po 'di tempo dall'ultima domanda, ma spero che questo aiuti qualcuno.

Come menzionato da @Cocomico, puoi fornire diversi punti di ingresso per l'applicazione nel file webpack.config.js. Se stai cercando una semplice configurazione Webpack (basata sull'idea di più punti di ingresso) che ti consenta di aggiungere componenti React a pagine statiche, potresti considerare di utilizzare questo: https://github.com/przemek-nowicki/multi-page -app-con-reagire


-1

Ti consiglio di dare un'occhiata a InertiaJS: https://inertiajs.com/

Con Inertia crei app proprio come hai sempre fatto con il tuo framework web lato server preferito. Utilizzi le funzionalità esistenti del tuo framework per routing, controller, middleware, autenticazione, autorizzazione, recupero dati e altro ancora.

L'unica cosa diversa è il tuo livello di visualizzazione. Invece di utilizzare il rendering lato server (es. Blade o modelli ERB), le viste sono componenti della pagina JavaScript. Ciò ti consente di costruire l'intero front-end utilizzando React, Vue o Svelte.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.