Kết xuất phía máy chủ ReactJS so với kết xuất phía máy khách


120

Tôi vừa mới bắt đầu nghiên cứu ReactJS và thấy rằng nó cung cấp cho bạn 2 cách để hiển thị trang: phía máy chủ và phía máy khách. Nhưng, tôi không thể hiểu cách sử dụng nó cùng nhau. Đây là 2 cách riêng biệt để xây dựng ứng dụng hay chúng có thể được sử dụng cùng nhau?

Nếu chúng ta có thể sử dụng nó cùng nhau, làm thế nào để làm điều đó - chúng ta có cần sao chép các phần tử giống nhau ở phía máy chủ và phía máy khách không? Hoặc, chúng ta có thể chỉ xây dựng các phần tĩnh của ứng dụng của chúng ta trên máy chủ và các phần động ở phía máy khách, mà không có bất kỳ kết nối nào với phía máy chủ đã được kết xuất trước không?


1
Câu trả lời ngắn gọn, KHÔNG - bạn có thể tách, gửi html tĩnh và thay đổi hoàn toàn nó trong kết xuất máy khách. Đã thêm chi tiết trong câu trả lời của tôi.
Kira

Câu trả lời:


108

Đối với một trang web / ứng dụng web nhất định, bạn có thể sử dụng phản ứng hoặc client-side , server-side hoặc cả hai .

Phía khách hàng

Đến đây, bạn đã hoàn toàn chạy ReactJS trên trình duyệt. Đây là cách thiết lập đơn giản nhất và bao gồm hầu hết các ví dụ (bao gồm các ví dụ trên http://reactjs.org ). HTML ban đầu được máy chủ hiển thị là một trình giữ chỗ và toàn bộ giao diện người dùng được hiển thị trong trình duyệt khi tất cả các tập lệnh của bạn tải.

Phía máy chủ

Hãy nghĩ về ReactJS như một công cụ tạo khuôn mẫu phía máy chủ ở đây (như ngọc bích, tay lái, v.v.). HTML được máy chủ hiển thị chứa giao diện người dùng như nó phải có và bạn không cần đợi bất kỳ tập lệnh nào tải. Trang của bạn có thể được lập chỉ mục bởi một công cụ tìm kiếm (nếu một công cụ không thực thi bất kỳ javascript nào).

Vì giao diện người dùng được hiển thị trên máy chủ, không có trình xử lý sự kiện nào của bạn hoạt động và không có tương tác (bạn có một trang tĩnh).

Cả hai

Ở đây, kết xuất ban đầu nằm trên máy chủ. Do đó, HTML mà trình duyệt nhận được có giao diện người dùng như nó vốn có. Sau khi các tập lệnh được tải, DOM ảo được hiển thị lại một lần nữa để thiết lập trình xử lý sự kiện của các thành phần của bạn.

Ở đây, bạn cần đảm bảo rằng bạn kết xuất lại chính xác cùng một DOM ảo (thành phần ReactJS gốc) với cùng một DOM propsmà bạn đã sử dụng để hiển thị trên máy chủ. Nếu không, ReactJS sẽ phàn nàn rằng DOM ảo phía máy chủ và phía máy khách không khớp.

Vì ReactJS khác biệt các DOM ảo giữa các lần hiển thị, nên DOM thực không bị thay đổi. Chỉ các trình xử lý sự kiện được liên kết với các phần tử DOM thực.


1
Vì vậy, trong trường hợp "cả hai" Tôi cần phải viết mã tương tự hai lần" một cho máy chủ rendering, và một để tái tạo DOM này trên máy khách phải không??
Simcha

10
Bạn cần chạy cùng một đoạn mã hai lần. Một lần trên máy chủ và một lần trên máy khách. Tuy nhiên, bạn cần phải viết các thành phần của mình để tính đến điều này - ví dụ: bạn không nên thực hiện bất kỳ tìm nạp dữ liệu không đồng bộ nào componentWillMount(), vì nó sẽ chạy cả máy khách và máy chủ. Bạn cũng sẽ cần một chiến lược để tìm nạp dữ liệu trước trên máy chủ và làm cho nó có sẵn để hiển thị ban đầu trên máy khách, để đảm bảo rằng bạn nhận được cùng một đầu ra.
Jonny Buchanan

3
Bạn cũng có thể kiểm tra xem mã đang được thực thi ở phía máy chủ hay phía máy khách bằng cách sử dụng typeof window == "undefined"và sau đó tìm nạp dữ liệu của bạn cho phù hợp.
Gautham Badhrinathan

Bạn có liên kết đến một ví dụ phù hợp với việc triển khai của bạn không?
Sawtaytoes

1
@IanW Thông thường trong trường hợp này, HTML được máy chủ trả về rất "thô", chỉ cần nhập JavaScript và các kiểu của bạn và chứa một <div>mà React sẽ ghi vào.
Matt Holland

48

Nguồn hình ảnh: Blog Kỹ thuật của Walmart Labs

SSR

CSR

NB: SSR (Kết xuất phía máy chủ), CSR (Kết xuất phía máy khách).

Sự khác biệt chính là với SSR, các máy chủ phản hồi với trình duyệt máy khách, bao gồm HTML của trang sẽ được hiển thị. Điều quan trọng cần lưu ý là mặc dù, với SSR, trang hiển thị nhanh hơn. Trang sẽ không sẵn sàng để người dùng tương tác cho đến khi các tệp JS được tải xuống và trình duyệt đã thực thi React.

Một nhược điểm là SSR TTFB (Thời gian đến Byte đầu tiên) có thể lâu hơn một chút. Có thể hiểu như vậy, vì máy chủ mất một khoảng thời gian để tạo tài liệu HTML, do đó làm tăng kích thước phản hồi của máy chủ.


4

Tôi thực sự đã tự hỏi nghiên cứu tương tự khá một chút và trong khi câu trả lời bạn đang tìm kiếm đã được đưa ra trong các nhận xét nhưng tôi cảm thấy nó nên nổi bật hơn vì vậy tôi đang viết bài đăng này (tôi sẽ cập nhật khi tôi có thể đưa ra cách tốt hơn vì tôi thấy giải pháp về mặt kiến ​​trúc ít nhất là có vấn đề).

Bạn sẽ cần phải viết các thành phần của mình với cả hai cách, do đó về cơ bản đặtif công tắc ở khắp mọi nơi để xác định xem bạn đang ở trên máy khách hay máy chủ và sau đó thực hiện dưới dạng truy vấn DB (hoặc bất kỳ điều gì thích hợp trên máy chủ) hoặc lệnh gọi REST (trên khách hàng). Sau đó, bạn sẽ phải viết các điểm cuối tạo ra dữ liệu của bạn và hiển thị nó cho khách hàng và bạn thực hiện.

Một lần nữa, rất vui khi tìm hiểu về một giải pháp sạch hơn.


2

Đây là 2 cách riêng biệt để xây dựng ứng dụng hay chúng có thể được sử dụng cùng nhau?

Chúng có thể được sử dụng cùng nhau.

Nếu chúng ta có thể sử dụng nó cùng nhau, làm thế nào để làm điều đó - chúng ta có cần sao chép các phần tử giống nhau ở phía máy chủ và phía máy khách không? Hoặc, chúng ta có thể chỉ xây dựng các phần tĩnh của ứng dụng của chúng ta trên máy chủ và các phần động ở phía máy khách, mà không có bất kỳ kết nối nào với phía máy chủ đã được kết xuất trước không?

Tốt hơn hết bạn nên có cùng một bố cục được kết xuất để tránh thao tác chỉnh lại và sơn lại, ít nhấp nháy / nhấp nháy hơn, trang của bạn sẽ mượt mà hơn. Tuy nhiên, nó không phải là một hạn chế. Bạn rất có thể lưu cache SSR html (một cái gì đó Electrode làm để giảm thời gian phản hồi) / gửi một html tĩnh bị ghi đè bởi CSR (kết xuất phía máy khách).

Nếu bạn chỉ mới bắt đầu với SSR, tôi khuyên bạn nên bắt đầu đơn giản, SSR có thể rất phức tạp rất nhanh. Để xây dựng html trên máy chủ có nghĩa là mất quyền truy cập vào các đối tượng như cửa sổ, tài liệu (bạn có những thứ này trên máy khách), mất khả năng kết hợp các hoạt động không đồng bộ (ngoài hộp) và nói chung là rất nhiều chỉnh sửa mã để mã của bạn tương thích với SSR ( vì bạn sẽ phải sử dụng webpack để đóng gói pack.js của mình). Những thứ như nhập CSS, yêu cầu và nhập đột nhiên bắt đầu cắn bạn (đây không phải là trường hợp trong ứng dụng React mặc định không có webpack).

Mô hình chung của SSR trông như thế này. Máy chủ Express phục vụ các yêu cầu:

const app = Express();
const port = 8092;

// This is fired every time the server side receives a request
app.use(handleRender);
function handleRender(req, res) {
    const fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
    console.log('fullUrl: ', fullUrl);
    console.log('req.url: ', req.url);

    // Create a new Redux store instance
    const store = createStore(reducerFn);

    const urlToRender = req.url;
    // Render the component to a string
    const html = renderToString(
        <Provider store={store}>
            <StaticRouter location={urlToRender} context={{}}>
                {routes}
            </StaticRouter>
        </Provider>
    );
    const helmet = Helmet.renderStatic();

    // Grab the initial state from our Redux store
    const preloadedState = store.getState();

    // Send the rendered page back to the client
    res.send(renderFullPage(helmet, html, preloadedState));
}

Đề xuất của tôi cho những người bắt đầu với SSR sẽ là cung cấp html tĩnh. Bạn có thể lấy html tĩnh bằng cách chạy ứng dụng CSR SPA:

document.getElementById('root').innerHTML

Đừng quên, lý do duy nhất để sử dụng SSR phải là:

  1. SEO
  2. Tải nhanh hơn (tôi sẽ giảm giá này)

Hack: https://medium.com/@gagan_goku/react-and-server-side-rendering-ssr-444d8c48abfc

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.