Sử dụng React trong một ứng dụng nhiều trang


122

Tôi đã chơi với React và cho đến nay tôi thực sự thích nó. Tôi đang xây dựng một ứng dụng với NodeJS và muốn sử dụng React cho một số thành phần tương tác trên ứng dụng. Tôi không muốn biến nó thành ứng dụng trang đơn.

Tôi chưa tìm thấy bất kỳ điều gì trên web trả lời các câu hỏi sau:

Làm cách nào để chia nhỏ hoặc nhóm các thành phần React của tôi trên một ứng dụng nhiều trang?

Hiện tại, tất cả các thành phần của tôi nằm trong một tệp mặc dù tôi có thể không bao giờ tải chúng trong một số phần của ứng dụng.

Cho đến nay, tôi đang thử sử dụng các câu lệnh có điều kiện để hiển thị các thành phần bằng cách tìm kiếm ID của vùng chứa nơi React sẽ hiển thị. Tôi không chắc 100% về các phương pháp hay nhất với React. Nó trông giống như thế này.

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

Tôi vẫn đang đọc tài liệu và chưa tìm thấy những gì tôi cần cho một ứng dụng nhiều trang.

Cảm ơn trước.


cố gắng sử dụng plugin requestjs.
amit_183

2
Nếu bạn không bận tâm rằng ReactJs là một thư viện JS rất lớn sẽ cần được khởi tạo cho mỗi trang (như bạn đã nói rằng bạn không xây dựng một ứng dụng trang duy nhất), thì tôi không chắc rằng điều đó quan trọng với bạn ' đã kết hợp tất cả các thành phần vào một tệp. Nó sẽ được lưu trữ trên máy khách. Khi một trang tải, hãy đặt nó renderđúng thành phần trong một scriptkhối.
WiredPrairie

Tôi đang gặp vấn đề tương tự: Tôi có một ứng dụng tải các thư viện lớn khác trên các trang khác nhau và tôi chỉ muốn tải phản ứng + một thư viện tùy thuộc vào nhu cầu của khách truy cập, thay vì bốn thư viện lớn chỉ trong trường hợp.
AJFarkas

Câu trả lời:


83

Hiện tại, tôi đang làm một việc tương tự.

Ứng dụng này không phải là Ứng dụng React đầy đủ, tôi đang sử dụng React cho Nội dung động, như CommentBox, là tính năng tự động đánh dấu. Và có thể được đưa vào bất kỳ Điểm nào với các thông số đặc biệt ..

Tuy nhiên, tất cả các Ứng dụng phụ của tôi đều được tải và đưa vào một tệp duy nhất all.js, do đó, trình duyệt có thể lưu vào bộ nhớ cache trên các trang.

Khi tôi cần đưa một Ứng dụng vào Mẫu SSR, tôi chỉ cần đưa một DIV có lớp "__react-root" và một ID đặc biệt, (tên của Ứng dụng React sẽ được hiển thị)

Logic thực sự đơn giản:

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>

Biên tập

Vì webpack hỗ trợ phân tách mã & LazyLoading một cách hoàn hảo, nên tôi nghĩ sẽ hợp lý khi đưa vào một ví dụ mà bạn không cần tải tất cả các ứng dụng của mình trong một gói mà hãy chia nhỏ chúng ra và tải theo yêu cầu.

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

1
Có vẻ tuyệt vời, có ai đã chạy ứng dụng này khi sử dụng npm create-react-app chưa? Tôi không nghĩ rằng điều này sẽ hiệu quả với tôi ... Tôi có nó đang chạy với 1 ứng dụng vừa rồi và có thể xem nó có thể hoạt động như thế nào nhưng bản dựng của tôi sẽ không tạo ra một bản dựng sản xuất hoạt động chính xác.
Sprose

@Sprose cũng nên hoạt động với create-react-app, tôi có thiếu thứ gì không? Có thể bạn có thể chia sẻ một ví dụ nhỏ trên github mà nó không làm như vậy, tôi không thấy lý do tại sao nó không nên
webdeb

1
@Sprose sry cho câu trả lời muộn, nhưng tôi nghĩ bạn đang thử một cái gì đó hoàn toàn khác, cách tiếp cận này cố gắng giải quyết vấn đề gì. IMO create react appcung cấp cho bạn một số công cụ dễ dàng để tạo bundle.js. Vì vậy, mục đích của câu trả lời của tôi là sử dụng giống nhau bundle.jsvà sử dụng nó trên nhiều trang SSR khác nhau và tải nhiều ứng dụng React khác nhau vào một trang duy nhất. Xin lỗi, nếu câu trả lời của tôi không phù hợp với nhu cầu của bạn, vui lòng tạo một Bài đăng mới và mô tả những gì bạn đang cố gắng làm, tôi sẽ cố gắng giúp bạn.
webdeb

1
@SorcererApprentice cra sử dụng webpack, bạn phải đẩy ra và sau đó kiểm tra kiến ​​thức cơ bản về webpack.js.org/guides/getting-started/#creating-a-bundle
webdeb Ngày

1
@SorcererApprentice về cơ bản ai đó đã đăng cấu hình webpack trên trang này: stackoverflow.com/a/41857199/5004923
webdeb Ngày

52

Bạn có thể cung cấp một số điểm nhập cho ứng dụng trong tệp 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'
  },
}

thì bạn có thể có trong thư mục src của mình ba tệp html khác nhau với các tệp js tương ứng của chúng (ví dụ cho trang1):

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

Tệp 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'))

Sau đó, các thành phần React khác nhau có thể được tải cho từng trang.


1
Tôi đọc về những điều dưới đây trong trang 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.Vì vậy, mẫu này có nên được cập nhật cho webpack 4+ không?
Ramesh

32

Tôi đang xây dựng một ứng dụng từ đầu và đang học hỏi trong quá trình thực hiện, nhưng tôi nghĩ thứ bạn đang tìm là React-Router . React-Router ánh xạ các thành phần của bạn tới các URL cụ thể. Ví dụ:

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)

Trong trường hợp tìm kiếm, 'thuật ngữ' có thể truy cập được dưới dạng thuộc tính trong AnimalSearchBox:

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

Hãy thử nó ra. Đây hướng dẫn là một trong đó đặt tôi trên đầu về hiểu biết của tôi về điều này và các chủ đề liên quan khác.


Câu trả lời ban đầu như sau:

Tôi đã tìm thấy cách của tôi ở đây để tìm kiếm câu trả lời tương tự. Xem nếu cái này bài đăng truyền cảm hứng cho bạn. Nếu ứng dụng của bạn giống như của tôi, nó sẽ có các khu vực thay đổi rất ít và chỉ thay đổi trong phần chính. Bạn có thể tạo một widget có trách nhiệm hiển thị một widget khác dựa trên trạng thái của ứng dụng. Sử dụng kiến ​​trúc dòng, bạn có thể thực hiện một hành động điều hướng thay đổi trạng thái mà tiện ích nội dung của bạn chuyển sang, chỉ cập nhật phần nội dung của trang một cách hiệu quả.

Đó là cách mà tôi đang cố gắng bây giờ.


8
Điều gì sẽ xảy ra nếu đường dẫn URL được tạo bởi mã phụ trợ của tôi (trong trường hợp này là nodejs)? Liệu Routercông việc có giống như cách nó làm trong một ứng dụng trang không?
Jose Carrillo

1
@Scott Điều gì xảy ra nếu tôi không muốn để lộ chức năng trang quản trị có các widget đặc biệt? Sử dụng react, bạn có thể tạo lại giao diện mà không cần xác thực.
Kairat Kempirbaev

11

Bạn có đang sử dụng CMS không? Họ có xu hướng thích thay đổi các url có thể phá vỡ ứng dụng của bạn.

Một cách khác là sử dụng một cái gì đó như React Habitat .

Với nó, bạn có thể đăng ký các thành phần và chúng tự động được tiếp xúc với dom.

Thí dụ

Đăng ký (các) thành phần:

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

Sau đó, chúng có sẵn trong dom của bạn như thế này:

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

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

Ở trên sẽ được tự động thay thế bằng các thành phần phản ứng của bạn.

Sau đó, bạn cũng có thể tự động chuyển các thuộc tính (hoặc đạo cụ) cho các thành phần của mình:

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

Điều này sẽ hiển thị sizenhư một chỗ dựa cho thành phần của bạn. Có các tùy chọn bổ sung để chuyển các kiểu khác như json, array's, ints, float, v.v.


2

Tôi biết đã lâu kể từ khi câu hỏi này được hỏi nhưng hy vọng điều này sẽ giúp ích cho ai đó.

Như @Cocomico đã đề cập, bạn có thể cung cấp một số điểm nhập cho ứng dụng trong tệp webpack.config.js. Nếu bạn đang tìm kiếm một thiết lập Webpack đơn giản (dựa trên ý tưởng về nhiều điểm nhập) cho phép bạn thêm các thành phần React vào các trang tĩnh, bạn có thể cân nhắc sử dụng cách này: https://github.com/przemek-nowicki/multi-page -app-with-react


-1

Tôi khuyên bạn nên xem InertiaJS: https://inertiajs.com/

Với Inertia, bạn xây dựng các ứng dụng giống như bạn đã luôn làm với khung web phía máy chủ mà bạn lựa chọn. Bạn sử dụng chức năng hiện có của khuôn khổ để định tuyến, bộ điều khiển, phần mềm trung gian, xác thực, ủy quyền, tìm nạp dữ liệu, v.v.

Điều duy nhất khác biệt là lớp xem của bạn. Thay vì sử dụng kết xuất phía máy chủ (ví dụ: mẫu Blade hoặc ERB), các chế độ xem là các thành phần trang JavaScript. Điều này cho phép bạn xây dựng toàn bộ giao diện người dùng của mình bằng React, Vue hoặc Svelte.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.