Изоморфный рендер потока на сервере после всех запросов

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

Например:

компонент A ‹- компонент B ‹- компонент C (C запускает действие, которое вызывает API и возвращает данные для рендеринга, тем временем просто рендерит «загрузку»).

При проверке моего исходного кода я вижу только «загрузку» и хотел бы, чтобы в целях SEO сервер ждал, пока вызов компонента C не будет разрешен и обработан.

Теоретически это звучит просто, потому что сервер должен сам вызвать это действие и дождаться завершения действия, а затем вызвать react.renderToString(), например:

server.get('/', function (req, res, next) {
    showMessages({}, function showMessagesCallback() { //add a callback
        var html = React.renderToString(ChatComponent());
        res.send(html);
    });
});

Но что, если несколько компонентов вызывают действия, и мне нужно дождаться решения нескольких действий, а затем вызвать renderToString

Вместо этого запросы принимаются на стороне клиента. Мой серверный файл:

/**
 * This leverages Express to create and run the http server.
 * A Fluxible context is created and executes the navigateAction
 * based on the URL. Once completed, the store state is dehydrated
 * and the application is rendered via React.
 */

import express from 'express';
import path from 'path';
import serialize from 'serialize-javascript';
import {navigateAction} from 'fluxible-router';
import debugLib from 'debug';
import React from 'react';
import app from './app';
import HtmlComponent from 'components/Html';
const htmlComponent = React.createFactory(HtmlComponent);

const debug = debugLib('quran-com');

const server = express();
server.set('state namespace', 'App');
server.use('/public', express.static(path.join(__dirname, '/build')));
server.use('/images', express.static(path.join(__dirname, '/client/images')));
server.use('/fonts', express.static(path.join(__dirname, '/client/styles/fonts')));

server.use((req, res, next) => {
    let context = app.createContext();

    debug('Executing navigate action');
    context.getActionContext().executeAction(navigateAction, {
        url: req.url
    }, (err) => {
        if (err) {
            if (err.status && err.status === 404) {
                next();
            } else {
                next(err);
            }
            return;
        }

        debug('Exposing context state');
        const exposed = 'window.App=' + serialize(app.dehydrate(context)) + ';';

        debug('Rendering Application component into html');
        const html = React.renderToStaticMarkup(htmlComponent({
            context: context.getComponentContext(),
            state: exposed,
            markup: React.renderToString(context.createElement())
        }));

        debug('Sending markup');
        res.type('html');
        res.write('<!DOCTYPE html>' + html);
        res.end();
    });
});

const port = process.env.PORT || 8000;
server.listen(port);
console.log('Listening on port ' + port);

export default server;

как лучше всего это сделать?


person Mohamed El Mahallawy    schedule 17.05.2015    source источник
comment
Я не понимаю, какую проблему вы пытаетесь решить. Какие данные должны быть отображены? Где оно взято?   -  person WiredPrairie    schedule 17.05.2015
comment
Что делает рендеринг на стороне сервера только тогда, когда все HTTP-запросы возвращены. иметь в виду? О каком наборе HTTP-запросов вы говорите? И что вы имеете в виду под возвратом? У вас есть конкретный пример?   -  person August Lilleaas    schedule 17.05.2015
comment
@WiredPrairie Я обновил вопрос, чтобы лучше объяснить   -  person Mohamed El Mahallawy    schedule 17.05.2015
comment
Вам нужно будет использовать метод задержки окончательного рендеринга до тех пор, пока все компоненты не получат свои данные или не централизуют запрос данных, и снова подождите.   -  person WiredPrairie    schedule 18.05.2015
comment
@WiredPrairie, хорошо, звучит хорошо - как это сделать? :)   -  person Mohamed El Mahallawy    schedule 18.05.2015
comment
Я считаю хорошим ответом на то, что он слишком длинный для StackOverflow.   -  person WiredPrairie    schedule 18.05.2015


Ответы (1)


Вам нужно переосмыслить архитектуру вашего приложения. Компоненты не должны сами получать данные, вам лучше, когда что-то дает им данные.

Мое предложение состояло бы в том, чтобы сделать это в действии навигации, чтобы оно стало точкой входа в любое представление. Затем здесь вы можете разрешить все необходимые данные и направить их в хранилища с этими данными, после разрешения вызовите обратный вызов. Например.:

module.exports = {

    navigateAction: function (context, state, done) {
        var completeNavigation = function () {
            context.dispatch('NAVIGATE_DONE');
            done()
        }

        var route = _.last(state.routes);

        debug('navigate to: ' + route.name);

        switch (route.name) {
            case 'products':
                context.executeAction(productActions.loadProducts, null, completeNavigation);
                break;
            default:
                completeNavigation();
                break;
        }

    }

};

В этом примере я использую react-router.

person Tomas Kirda    schedule 17.05.2015
comment
Я с вами в хранилищах, хранящих данные и отправляющих их в компоненты. +1 за это. Мне нравится ваш подход к некоторым действиям, которые вызывает сервер, в качестве первого шага, который ждет, пока все остальное разрешится. Можно я не просто за .waitFor по всем магазинам? - person Mohamed El Mahallawy; 18.05.2015