Usando o React em um aplicativo de várias páginas

122

Eu tenho brincado com o React e até agora eu realmente gosto. Estou criando um aplicativo com o NodeJS e gostaria de usar o React para alguns dos componentes interativos no aplicativo. Eu não quero torná-lo aplicativo de página única.

Ainda não encontrei nada na web que responda às seguintes perguntas:

Como separo ou agrupo meus componentes do React em um aplicativo de várias páginas?

Atualmente, todos os meus componentes estão em um arquivo, mesmo que eu nunca os carregue em algumas seções do aplicativo.

Até agora, estou tentando usar instruções condicionais para renderizar componentes pesquisando o ID do contêiner no qual o React será renderizado. Não tenho 100% de certeza sobre quais são as melhores práticas com o React. Parece algo assim.

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

Ainda estou lendo a documentação e ainda não encontrei o que preciso para um aplicativo de várias páginas.

Desde já, obrigado.

Jose Carrillo
fonte
tente usar o plugin requirejs.
amit_183
2
Se você não se importa que o ReactJs seja uma biblioteca JS muito grande que precisará ser inicializada para cada página (como você disse que não está criando um aplicativo de página única), não tenho certeza se é importante que você ' você combinou todos os componentes em um arquivo. Ele será armazenado em cache no cliente. Quando uma página é carregada, coloque rendero componente correto em um scriptbloco.
WiredPrairie
Estou com o mesmo problema: tenho um aplicativo que carrega outras bibliotecas grandes em páginas diferentes e prefiro carregar o react + uma biblioteca dependendo das necessidades do visitante, em vez de quatro bibliotecas grandes apenas por precaução.
AJFarkas 02/05

Respostas:

83

Atualmente, estou fazendo algo semelhante.

O aplicativo não é um aplicativo React completo, estou usando o React para coisas dinâmicas, como o CommentBox, que é autark. E pode ser incluído em qualquer ponto com parâmetros especiais.

No entanto, todos os meus sub-aplicativos são carregados e incluídos em um único arquivo all.js, para que possam ser armazenados em cache pelo navegador entre as páginas.

Quando preciso incluir um aplicativo nos modelos SSR, só preciso incluir um DIV com a classe "__react-root" e um ID especial (o nome do aplicativo de reação a ser renderizado)

A lógica é realmente simples:

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

Como o webpack suporta perfeitamente a divisão de código e o LazyLoading, achei bom incluir um exemplo em que você não precisa carregar todos os aplicativos em um único pacote, mas dividi-los e carregá-los sob demanda.

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
fonte
1
Parece ótimo, alguém está executando isso ao usar o npm create-react-app? Eu não acho que isso funcionaria para mim ... Eu o tenho em execução com o aplicativo 1 agora e posso ver como ele poderia funcionar, mas minha compilação não criará uma compilação de produção que funcione corretamente.
Sprose
O @Sprose também deve funcionar com o create-react-app, estou perdendo alguma coisa? Talvez você possa compartilhar um pequeno exemplo no github, onde isso não acontecer, eu não vejo uma razão pela qual should't
webdeb
1
@ Prose sry para a resposta tardia, mas acho que você está tentando algo completamente diferente, o que essa abordagem tenta resolver. O IMO create react appfornece ferramentas fáceis de criar bundle.js. Portanto, o objetivo da minha resposta é usar o mesmo bundle.jse usá-lo em vários sites SSR e carregar muitos aplicativos React diferentes em uma única página. Desculpe, se minha resposta não se adequar às suas necessidades, fique à vontade para criar uma nova postagem e descrever o que você está tentando fazer, tentarei ajudá-lo.
Webdeb
1
O @SorcererApprentice cra usa o webpack, você deve ejetar e fazer o checkout do básico webpack.js.org/guides/getting-started/#creating-a-bundle
webdeb
1
@SorcererApprentice basicamente alguém postou a configuração do webpack nesta página: stackoverflow.com/a/41857199/5004923
webdeb
52

Você pode fornecer vários pontos de entrada para o aplicativo no arquivo 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'
  },
}

você pode ter na pasta src três arquivos html diferentes com seus respectivos arquivos js (exemplo para a página 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>

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

Diferentes componentes do React podem ser carregados para cada página.

Cocomico
fonte
1
Eu li sobre o abaixo na página 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.Portanto, este exemplo deve ser atualizado para o webpack 4+?
Ramesh
32

Estou construindo um aplicativo desde o início e aprendendo à medida que passo, mas acho que o que você está procurando é o React-Router . O React-Router mapeia seus componentes para URLs específicos. Por exemplo:

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)

No caso de pesquisa, 'termo' pode ser acessado como uma propriedade no AnimalSearchBox:

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

Experimente. Este tutorial foi o que me destacou em termos de compreensão deste e de outros tópicos relacionados.


A resposta original segue:

Eu encontrei o meu caminho aqui procurando a mesma resposta. Veja se este post o inspira. Se o seu aplicativo for como o meu, ele terá áreas que mudam muito pouco e variam apenas no corpo principal. Você pode criar um widget cuja responsabilidade é renderizar um widget diferente com base no estado do aplicativo. Usando uma arquitetura de fluxo, você pode despachar uma ação de navegação que altera o estado em que seu widget de corpo muda, atualizando efetivamente apenas o corpo da página.

Essa é a abordagem que estou tentando agora.

Scott
fonte
8
E se o caminho da URL for criado pelo meu código de back-end (neste caso, nodejs)? Funcionará da Routermesma maneira que em um aplicativo de página única?
Jose Carrillo
1
@ Scott E se eu não quiser expor a funcionalidade da página de administrador que possui widgets especiais? Usando react, é possível recriar a aparência sem a autenticação real.
Kairat Kempirbaev
11

Você está usando um CMS? Eles tendem a gostar de alterar os URLs que podem interromper seu aplicativo.

Outra maneira é usar algo como React Habitat .

Com ele, você pode registrar componentes e eles são automaticamente expostos ao dom.

Exemplo

Registrar componente (s):

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

Então eles estão disponíveis no seu domínio assim:

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

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

O acima será automaticamente substituído pelos seus componentes de reação.

Você também pode passar automaticamente propriedades (ou suportes) para seus componentes:

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

Isso será exposto sizecomo um suporte ao seu componente. Existem opções adicionais para passar outros tipos, como json, array, ints, floats etc.

jennas
fonte
2

Eu sei que já faz um tempo desde que essa pergunta foi feita, mas espero que isso ajude alguém.

Como o @Cocomico mencionou, você pode fornecer vários pontos de entrada para o aplicativo no arquivo webpack.config.js. Se você estiver procurando por uma configuração simples do Webpack (com base na idéia de vários pontos de entrada) que permita adicionar componentes do React a páginas estáticas, considere o seguinte: https://github.com/przemek-nowicki/multi-page -app-with-react

Przemek Nowicki
fonte
-1

Sugiro que você dê uma olhada no InertiaJS: https://inertiajs.com/

Com o Inertia, você cria aplicativos como sempre fez com a estrutura da web do lado do servidor de sua escolha. Você usa a funcionalidade existente da sua estrutura para roteamento, controladores, middleware, autenticação, autorização, busca de dados e muito mais.

A única coisa diferente é a sua camada de visualização. Em vez de usar a renderização do lado do servidor (por exemplo, modelos Blade ou ERB), as visualizações são componentes da página JavaScript. Isso permite que você crie todo o seu front-end usando React, Vue ou Svelte.

Agu Dondo
fonte