Verwenden von React in einer mehrseitigen App

122

Ich habe mit React herumgespielt und bis jetzt mag ich es wirklich. Ich erstelle eine App mit NodeJS und möchte React für einige der interaktiven Komponenten in der gesamten Anwendung verwenden. Ich möchte es nicht zu einer einseitigen App machen.

Ich habe noch nichts im Internet gefunden, das die folgenden Fragen beantwortet:

Wie kann ich meine React-Komponenten in einer mehrseitigen App aufteilen oder bündeln?

Derzeit befinden sich alle meine Komponenten in einer Datei, obwohl ich sie in einigen Abschnitten der App möglicherweise nie laden werde.

Bisher versuche ich, bedingte Anweisungen zum Rendern von Komponenten zu verwenden, indem ich nach der ID des Containers suche, in dem React gerendert wird. Ich bin mir nicht 100% sicher, welche Best Practices bei React angewendet werden. Es sieht ungefähr so ​​aus.

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

Ich lese immer noch die Dokumentation und habe noch nicht gefunden, was ich für eine mehrseitige App benötige.

Danke im Voraus.

Jose Carrillo
quelle
Versuchen Sie, das Plugin requirejs zu verwenden.
amit_183
2
Wenn es Ihnen nichts ausmacht, dass ReactJs eine sehr große JS-Bibliothek ist, die für jede Seite initialisiert werden muss (wie Sie sagten, Sie erstellen keine App für eine einzelne Seite), bin ich mir nicht sicher, ob es darauf ankommt, dass Sie Wir haben alle Komponenten in einer Datei zusammengefasst. Es wird auf dem Client zwischengespeichert. Wenn eine Seite geladen wird, muss sie renderdie richtige Komponente in einem scriptBlock haben.
WiredPrairie
Ich habe das gleiche Problem: Ich habe eine App, die andere große Bibliotheken auf verschiedenen Seiten lädt, und ich lade lieber Reagieren + eine Bibliothek je nach den Bedürfnissen des Besuchers, anstatt vier große Bibliotheken für alle Fälle.
AJFarkas

Antworten:

83

Derzeit mache ich etwas Ähnliches.

Die Anwendung ist keine vollständige React-App. Ich verwende React für dynamische Inhalte wie CommentBox, die autark ist. Und kann an jedem Punkt mit speziellen Parametern aufgenommen werden.

Alle meine Unter-Apps werden jedoch geladen und in eine einzelne Datei aufgenommen all.js, sodass sie vom Browser seitenübergreifend zwischengespeichert werden können.

Wenn ich eine App in die SSR-Vorlagen aufnehmen muss, muss ich nur einen DIV mit der Klasse "__react-root" und einer speziellen ID (den Namen der zu rendernden React-App) einfügen.

Die Logik ist wirklich einfach:

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>

Bearbeiten

Da Webpack Code-Splitting und LazyLoading perfekt unterstützt, hielt ich es für sinnvoll, ein Beispiel aufzunehmen, in dem Sie nicht alle Ihre Apps in einem Bundle laden müssen, sondern sie aufteilen und bei Bedarf laden müssen.

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
quelle
1
Sieht gut aus, hat jemand dies zum Laufen gebracht, wenn er die npm create-react-app verwendet? Ich glaube nicht, dass dies für mich funktionieren würde ... Ich habe es gerade mit der 1-App ausgeführt und kann sehen, wie es funktionieren könnte, aber mein Build erstellt keinen Produktions-Build, der korrekt funktioniert.
Sprose
@Sprose sollte auch mit der Create-React-App funktionieren. Fehlt mir etwas? Vielleicht können Sie ein kleines Beispiel auf Github teilen, wo dies nicht der Fall ist. Ich sehe keinen Grund, warum dies nicht der Fall sein sollte
Webdeb
1
@Sprose sry für die späte Antwort, aber ich denke, Sie versuchen etwas völlig anderes, was dieser Ansatz zu lösen versucht. IMO create react appbietet Ihnen einige einfache Werkzeuge zum Erstellen bundle.js. Der Zweck meiner Antwort besteht also darin, dasselbe zu verwenden bundle.jsund es auf mehreren SSR-Sites zu verwenden und viele verschiedene React-Anwendungen auf eine einzige Seite zu laden. Entschuldigung, wenn meine Antwort nicht Ihren Anforderungen entspricht, können Sie gerne einen neuen Beitrag erstellen und beschreiben, was Sie versuchen. Ich würde versuchen, Ihnen zu helfen.
Webdeb
1
@SorcererApprentice cra verwendet Webpack, Sie müssen die Grundlagen auswerfen und dann überprüfen webpack.js.org/guides/getting-started/#creating-a-bundle
webdeb
1
@SorcererApprentice Im Grunde hat jemand die Webpack-Konfiguration auf dieser Seite gepostet: stackoverflow.com/a/41857199/5004923
webdeb
52

In der Datei webpack.config.js können Sie mehrere Einstiegspunkte für die Anwendung angeben:

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'
  },
}

dann können Sie in Ihrem src-Ordner drei verschiedene HTML-Dateien mit ihren jeweiligen js-Dateien haben (Beispiel für Seite 1):

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

JavaScript-Datei:

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

Anschließend können für jede einzelne Seite verschiedene React-Komponenten geladen werden.

Cocomico
quelle
1
Ich habe darüber auf der Webex-Seite gelesen. 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.Sollte dieses Beispiel für Webpack 4+ aktualisiert werden?
Ramesh
32

Ich erstelle eine Anwendung von Grund auf und lerne, während ich gehe, aber ich denke, was Sie suchen, ist React-Router . React-Router ordnet Ihre Komponenten bestimmten URLs zu. Beispielsweise:

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)

Im Suchfall ist 'Begriff' als Eigenschaft in der AnimalSearchBox zugänglich:

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

Versuch es. Dieses Tutorial hat mich in Bezug auf mein Verständnis dieses und anderer verwandter Themen übertrieben.


Die ursprüngliche Antwort folgt:

Ich fand meinen Weg hierher und suchte nach der gleichen Antwort. Sehen Sie, ob dieser Beitrag Sie inspiriert. Wenn Ihre Anwendung so etwas wie meine ist, hat sie Bereiche, die sich nur sehr wenig ändern und nur im Hauptteil variieren. Sie können ein Widget erstellen, dessen Aufgabe es ist, basierend auf dem Status der Anwendung ein anderes Widget zu rendern. Mithilfe einer Flussarchitektur können Sie eine Navigationsaktion auslösen, die den Status ändert, in den Ihr Body-Widget wechselt, und so nur den Body der Seite effektiv aktualisieren.

Das ist der Ansatz, den ich jetzt versuche.

Scott
quelle
8
Was passiert, wenn der URL-Pfad von meinem Backend-Code (in diesem Fall nodejs) erstellt wird? Funktioniert Routerdas genauso wie in einer App mit nur einer Seite?
Jose Carrillo
1
@Scott Was ist, wenn ich keine Funktionen für Administrationsseiten mit speziellen Widgets verfügbar machen möchte? Mit React ist es möglich, das Erscheinungsbild ohne echte Authentifizierung wiederherzustellen.
Kairat Kempirbaev
11

Verwenden Sie ein CMS? Sie neigen dazu, URLs zu ändern, die Ihre Anwendung beschädigen könnten.

Ein anderer Weg ist die Verwendung von React Habitat .

Damit können Sie Komponenten registrieren und diese werden automatisch dem Dom ausgesetzt.

Beispiel

Registerkomponente (n):

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

Dann sind sie in Ihrem Dom wie folgt verfügbar:

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

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

Das Obige wird automatisch durch Ihre Reaktionskomponenten ersetzt.

Sie können dann auch automatisch Eigenschaften (oder Requisiten) an Ihre Komponenten übergeben:

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

Dies wird sizeals Requisite für Ihre Komponente angezeigt. Es gibt zusätzliche Optionen zum Übergeben anderer Typen wie JSON, Arrays, Ints, Floats usw.

Jennas
quelle
2

Ich weiß, dass diese Frage schon eine Weile her ist, aber hoffentlich hilft das jemandem.

Wie bei @Cocomico erwähnt, können Sie in der Datei webpack.config.js mehrere Einstiegspunkte für die Anwendung angeben. Wenn Sie nach einem einfachen Webpack-Setup suchen (basierend auf der Idee mehrerer Einstiegspunkte), mit dem Sie statischen Seiten React-Komponenten hinzufügen können, können Sie dies in Betracht ziehen: https://github.com/przemek-nowicki/multi-page -app-mit-reagieren

Przemek Nowicki
quelle
-1

Ich schlage vor, Sie werfen einen Blick auf InertiaJS: https://inertiajs.com/

Mit Inertia erstellen Sie Apps, wie Sie es immer mit dem serverseitigen Webframework Ihrer Wahl getan haben. Sie verwenden die vorhandenen Funktionen Ihres Frameworks für Routing, Controller, Middleware, Authentifizierung, Autorisierung, Datenabruf und mehr.

Das einzige, was anders ist, ist Ihre Ansichtsebene. Anstatt serverseitiges Rendering zu verwenden (z. B. Blade- oder ERB-Vorlagen), sind die Ansichten JavaScript-Seitenkomponenten. Auf diese Weise können Sie Ihr gesamtes Frontend mit React, Vue oder Svelte erstellen.

Agu Dondo
quelle