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

Я играю с 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')
    );
}

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

Спасибо заранее.

Ответ 1

В настоящее время я занимаюсь чем-то похожим.

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

Однако все мои вспомогательные приложения загружаются и включаются в один файл 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>

Edit

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

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

Ответ 2

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

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 могут быть загружены для каждой отдельной страницы.

Ответ 3

Я создаю приложение с нуля и учусь по ходу дела, но я думаю, что вы ищете 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
}

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


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

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

Это подход, который я пытаюсь сейчас.

Ответ 4

Используете ли вы 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, ints, float и т.д.

Ответ 5

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

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