Usar React en una aplicación de varias páginas

122

He estado jugando con React y hasta ahora me gusta mucho. Estoy creando una aplicación con NodeJS y me gustaría usar React para algunos de los componentes interactivos de la aplicación. No quiero que sea una aplicación de una sola página.

Todavía no he encontrado nada en la web que responda a las siguientes preguntas:

¿Cómo puedo dividir o agrupar mis componentes de React en una aplicación de varias páginas?

Actualmente, todos mis componentes están en un archivo, aunque es posible que nunca los cargue en algunas secciones de la aplicación.

Hasta ahora, estoy tratando de usar declaraciones condicionales para representar componentes buscando el ID del contenedor donde reaccionará. No estoy 100% seguro de cuáles son las mejores prácticas con React. Se parece a esto.

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

Todavía estoy leyendo la documentación y todavía no he encontrado lo que necesito para una aplicación de varias páginas.

Gracias por adelantado.

Jose Carrillo
fuente
intente utilizar el complemento requirejs.
amit_183
2
Si no le importa que ReactJs sea una biblioteca JS muy grande que deberá inicializarse para cada página (como dijo que no está creando una aplicación de una sola página), entonces no estoy seguro de que importe que usted ' he combinado todos los componentes en un archivo. Se almacenará en caché en el cliente. Cuando se carga una página, tenga renderel componente correcto en un scriptbloque.
WiredPrairie
Tengo el mismo problema: tengo una aplicación que carga otras bibliotecas grandes en diferentes páginas, y prefiero simplemente cargar react + una biblioteca según las necesidades del visitante, en lugar de cuatro bibliotecas grandes por si acaso.
AJFarkas

Respuestas:

83

Actualmente, estoy haciendo algo similar.

La aplicación no es una aplicación React completa, estoy usando React para cosas dinámicas, como CommentBox, que es autark. Y se puede incluir en cualquier Punto con parámetros especiales.

Sin embargo, todas mis aplicaciones secundarias se cargan e incluyen en un solo archivo all.js, por lo que el navegador puede almacenarlo en caché en todas las páginas.

Cuando necesito incluir una aplicación en las plantillas SSR, solo tengo que incluir un DIV con la clase "__react-root" y una ID especial (el nombre de la aplicación React que se va a renderizar)

La lógica es realmente simple:

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>

Editar

Dado que el paquete web admite perfectamente la división de código y LazyLoading, pensé que tenía sentido incluir un ejemplo en el que no necesita cargar todas sus aplicaciones en un paquete, sino dividirlas y cargarlas a pedido.

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
fuente
1
Se ve muy bien, ¿alguien ha ejecutado esto al usar npm create-react-app? No creo que esto funcione para mí ... Lo tengo ejecutándose con la aplicación 1 en este momento y puedo ver cómo podría funcionar, pero mi compilación no creará una compilación de producción que funcione correctamente.
Sprose
@Sprose también debería funcionar con create-react-app, ¿me estoy perdiendo algo? Tal vez pueda compartir un pequeño ejemplo en github donde no lo hace, no veo una razón por la que no debería hacerlo
webdeb
1
@Sprose sry por la respuesta tardía, pero creo que estás intentando algo completamente diferente, lo que este enfoque intenta resolver. La OMI create react apple ofrece herramientas fáciles de crear bundle.js. Entonces, el propósito de mi respuesta es usar el mismo bundle.jsy usarlo en múltiples sitios SSR, y cargar muchas aplicaciones React diferentes en una sola página. Lo siento, si mi respuesta no se ajusta a sus necesidades, no dude en crear una nueva publicación y describir lo que está tratando de hacer, trataría de ayudarlo.
webdeb
1
@SorcererApprentice cra usa webpack, tienes que expulsar y luego verificar
webdeb
1
@SorcererApprentice básicamente alguien publicó la configuración del paquete web en esta página: stackoverflow.com/a/41857199/5004923
webdeb
52

Puede proporcionar varios puntos de entrada para la aplicación en el archivo 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'
  },
}

entonces puede tener en su carpeta src tres archivos html diferentes con sus respectivos archivos js (ejemplo para 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>

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

A continuación, se pueden cargar diferentes componentes de React para cada página.

Cocomico
fuente
1
Leí sobre lo siguiente en la página de 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.Entonces, ¿debería actualizarse esta muestra para webpack 4+?
Ramesh
32

Estoy construyendo una aplicación desde cero y voy aprendiendo sobre la marcha, pero creo que lo que estás buscando es React-Router . React-Router asigna sus componentes a URL específicas. Por ejemplo:

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)

En el caso de búsqueda, se puede acceder a 'término' como una propiedad en AnimalSearchBox:

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

Pruébalo. Este tutorial es el que me puso en la cima en términos de mi comprensión de este y otros temas relacionados.


La respuesta original es la siguiente:

Encontré mi camino aquí buscando la misma respuesta. Mira si esta publicación te inspira. Si su aplicación es como la mía, tendrá áreas que cambian muy poco y varían solo en el cuerpo principal. Puede crear un widget cuya responsabilidad sea representar un widget diferente en función del estado de la aplicación. Usando una arquitectura de flujo, podría enviar una acción de navegación que cambie el estado en el que cambia el widget de su cuerpo, actualizando de manera efectiva solo el cuerpo de la página.

Ese es el enfoque que estoy intentando ahora.

Scott
fuente
8
¿Qué pasa si la ruta de la URL es creada por mi código de backend (nodejs en este caso)? ¿ RouterFuncionará de la misma manera que lo hace en una aplicación de una sola página?
Jose Carrillo
1
@Scott ¿Qué sucede si no quiero exponer la funcionalidad de la página de administración que tiene widgets especiales? Con react es posible recrear la apariencia sin autenticación real.
Kairat Kempirbaev
11

¿Estás usando un CMS? A ellos les suele gustar cambiar las URL, lo que podría dañar tu aplicación.

Otra forma es usar algo como React Habitat .

Con él, puede registrar componentes y automáticamente quedan expuestos al dom.

Ejemplo

Registrar componente (s):

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

Entonces están disponibles en tu dom así:

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

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

Lo anterior se reemplazará automáticamente con sus componentes de reacción.

Luego, también puede pasar propiedades (o accesorios) automáticamente a sus componentes:

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

Esto lo expondrá sizecomo apoyo a su componente. Hay opciones adicionales para pasar otros tipos como json, array's, ints, floats, etc.

Jennas
fuente
2

Sé que ha pasado un tiempo desde que se hizo esta pregunta, pero espero que esto ayude a alguien.

Como mencionó @Cocomico, podría proporcionar varios puntos de entrada para la aplicación en el archivo webpack.config.js. Si está buscando una configuración de Webpack simple (basada en la idea de múltiples puntos de entrada) que le permita agregar componentes React a páginas estáticas, puede considerar usar esto: https://github.com/przemek-nowicki/multi-page -app-with-react

Przemek Nowicki
fuente
-1

Te sugiero que eches un vistazo a InertiaJS: https://inertiajs.com/

Con Inertia puede crear aplicaciones como siempre lo ha hecho con el marco web del lado del servidor que elija. Utiliza la funcionalidad existente de su marco para enrutamiento, controladores, middleware, autenticación, autorización, obtención de datos y más.

Lo único que es diferente es su capa de vista. En lugar de utilizar la representación del lado del servidor (por ejemplo, las plantillas Blade o ERB), las vistas son componentes de página de JavaScript. Esto le permite construir su interfaz completa usando React, Vue o Svelte.

Agu Dondo
fuente