Использование React в многостраничном приложении

122

Я играл с React, и пока он мне очень нравится. Я создаю приложение с помощью NodeJS и хотел бы использовать React для некоторых интерактивных компонентов в приложении. Я не хочу делать это одностраничным приложением.

Я еще не нашел в сети ничего, что отвечало бы на следующие вопросы:

Как разделить или связать компоненты React в многостраничном приложении?

В настоящее время все мои компоненты находятся в одном файле, хотя я могу никогда не загрузить их в некоторых разделах приложения.

Пока я пытаюсь использовать условные операторы для визуализации компонентов, ища идентификатор контейнера, в котором будет отображаться React. Я не на 100% уверен, что лучше всего использовать с React. Это выглядит примерно так.

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

Я все еще читаю документацию и еще не нашел то, что мне нужно для многостраничного приложения.

Заранее спасибо.

Хосе Каррильо
источник
попробуйте использовать плагин requirejs.
amit_183
2
Если вы не возражаете, что ReactJs - это очень большая библиотека JS, которую нужно будет инициализировать для каждой страницы (как вы сказали, вы не создаете одностраничное приложение), то я не уверен, что это имеет значение, что вы ' Мы объединили все компоненты в один файл. Он будет кэширован на клиенте. Когда страница загружается, укажите renderправильный компонент в scriptблоке.
WiredPrairie,
У меня та же проблема: у меня есть приложение, которое загружает другие большие библиотеки на разных страницах, и я бы предпочел просто загрузить реакцию + одну библиотеку в зависимости от потребностей посетителя, а не четыре большие библиотеки на всякий случай.
AJFarkas

Ответы:

83

В настоящее время я делаю нечто подобное.

Приложение не является полноценным приложением React, я использую React для динамических материалов, например CommentBox, который является автарком. И может быть включен в любой точке со специальными параметрами ..

Однако все мои дополнительные приложения загружаются и включаются в один файл all.js, поэтому он может кэшироваться браузером на всех страницах.

Когда мне нужно включить приложение в шаблоны SSR, мне просто нужно включить DIV с классом «__react-root» и специальным идентификатором (имя приложения React, которое будет отображаться)

Логика действительно проста:

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>

редактировать

Поскольку webpack отлично поддерживает разделение кода и отложенную загрузку, я подумал, что имеет смысл включить пример, в котором вам не нужно загружать все свои приложения в один пакет, а разбивать их и загружать по запросу.

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
источник
1
Выглядит отлично, у кого-нибудь это работает при использовании npm create-response-app? Я не думаю, что это сработает для меня ... У меня сейчас он работает с приложением 1, и я вижу, как это может работать, но моя сборка не создаст производственную сборку, которая работает правильно.
Sprose
@Sprose тоже должен работать с приложением create-react-app, я что-то упустил? Может быть, вы можете поделиться небольшим примером на github, где его нет, я не вижу причин, почему это не должно быть
webdeb
1
@Sprose извиняюсь за поздний ответ, но я думаю, что вы пробуете что-то совершенно другое, что этот подход пытается решить. IMO create react appдает вам несколько простых инструментов для создания bundle.js. Итак, цель моего ответа - использовать одно bundle.jsи то же и использовать его на нескольких сайтах SSR и загрузить множество различных приложений React на одну страницу. Извините, если мой ответ не соответствует вашим потребностям, не стесняйтесь создавать новый пост и описывать то, что вы пытаетесь сделать, я постараюсь вам помочь.
webdeb 01
1
@SorcererApprentice cra использует webpack, вам нужно извлечь, а затем проверить
webdeb
1
@SorcererApprentice в основном кто-то разместил конфигурацию webpack на этой странице: stackoverflow.com/a/41857199/5004923
webdeb
52

Вы можете указать несколько точек входа для приложения в файле 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'
  },
}

тогда вы можете иметь в своей папке src три разных файла html с соответствующими файлами js (например, для 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>

Файл 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'))

Затем для каждой отдельной страницы могут быть загружены различные компоненты React.

Cocomico
источник
1
Я прочитал об этом ниже на странице 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.Итак, следует ли обновить этот образец для webpack 4+?
Рамеш
32

Я создаю приложение с нуля и учусь по ходу дела, но я думаю, что вам нужен React-Router . React-Router сопоставляет ваши компоненты с определенными URL-адресами. Например:

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)

В случае поиска "термин" доступен как свойство в AnimalSearchBox:

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

Попробуйте сами. Это руководство помогло мне лучше понять эту и другие связанные темы.


Исходный ответ следует:

Я нашел свой путь сюда в поисках того же ответа. Посмотрите, вдохновляет ли вас этот пост. Если ваше приложение чем-то похожее на мое, в нем будут области, которые очень мало изменяются и варьируются только в основном теле. Вы можете создать виджет, который должен отображать другой виджет в зависимости от состояния приложения. Используя архитектуру потока, вы можете отправить действие навигации, которое изменяет состояние, на которое переключается ваш основной виджет, эффективно обновляя только тело страницы.

Я сейчас пытаюсь это сделать.

Скотт
источник
8
Что, если путь URL-адреса создается моим внутренним кодом (в данном случае - nodejs)? Будет ли Routerработать так же, как в одностраничном приложении?
Jose Carrillo
1
@Scott Что делать, если я не хочу раскрывать функции административной страницы со специальными виджетами? Используя react, можно воссоздать внешний вид без реальной аутентификации.
Кайрат Кемпирбаев
11

Вы используете CMS? Им нравится менять URL-адреса, что может нарушить работу вашего приложения.

Другой способ - использовать что-то вроде React Habitat .

С его помощью вы можете регистрировать компоненты, и они автоматически становятся доступными для dom.

пример

Зарегистрируйте компонент (ы):

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

Тогда они будут доступны в вашем доме следующим образом:

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

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

Вышеуказанное будет автоматически заменено вашими реагирующими компонентами.

Затем вы можете автоматически передавать свойства (или реквизиты) своим компонентам:

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

Это станет sizeопорой для вашего компонента. Есть дополнительные параметры для передачи других типов, таких как json, array, int, float и т. Д.

Дженна
источник
2

Я знаю, что этот вопрос давно не задавали, но, надеюсь, это кому-то поможет.

Как упоминалось в @Cocomico, вы можете указать несколько точек входа для приложения в файле webpack.config.js. Если вы ищете простую настройку Webpack (основанную на идее нескольких точек входа), которая позволяет добавлять компоненты React на статические страницы, вы можете рассмотреть возможность использования этого: https://github.com/przemek-nowicki/multi-page -app-с-реагируют

Пшемек Новицки
источник
-1

Предлагаю вам взглянуть на InertiaJS: https://inertiajs.com/

С помощью Inertia вы создаете приложения так же, как вы всегда это делали с выбранной вами серверной веб-структурой. Вы используете существующие функциональные возможности вашей платформы для маршрутизации, контроллеров, промежуточного программного обеспечения, аутентификации, авторизации, выборки данных и многого другого.

Единственное, что отличается, - это ваш слой просмотра. Вместо использования рендеринга на стороне сервера (например, Blade-шаблонов или ERB-шаблонов) представления являются компонентами страницы JavaScript. Это позволяет вам создавать весь интерфейс с помощью React, Vue или Svelte.

Агу Дондо
источник