Подтвердить что ты не робот

Делая спокойный вызов api от js

Я делаю POC для изоморфного приложения javascript для рендеринга html со стороны сервера. POC работает с простым html, но я хочу сделать api-вызов и получить ответ json и отправить функцию рендеринга. Я пробовал разные способы, но он не работает. Может кто-нибудь из вас, пожалуйста, сообщите мне, где мне не хватает.

Я очень недавно реагирую на js, и любая помощь будет действительно оценена

loadCategoriesFromServer: function() {
        var self = this;

// get walking directions from central park to the empire state building
    var http = require("http");
    url = "api url here";
        var request = http.get(url, function (response) {
            // data is streamed in chunks from the server
            // so we have to handle the "data" event    
            var buffer = "", 
                data,
                route;

            response.on("data", function (chunk) {
                buffer += chunk;
            }); 

            response.on("end", function (err) {

              data = JSON.parse(buffer);

              //console.log(data.d);
              //console.log(data.d.Items);
                self.setState({
                    categories: data.d.Items
                });
            }); 
        });
    }, // load from server end

    getInitialState: function() {
        return { categories: [] };
    },

    componentWillMount: function() {
        console.log("calling load categories")
        this.loadCategoriesFromServer();
    },
render: function () {

        //console.log("data");
        //console.log(this.state.categories);

        var postNodes = this.state.categories.map(function (cat) {
          console.log(cat);
        });

        return (
          <div id="table-area">
             //i want to paint the data here..
          </div>
        )
      }

  });
4b9b3361

Ответ 1

Извлечение внутри компонента с помощью componentWillMount не является подходящим местом, если вам необходимо отобразить серверную часть. Вам нужно как-то переместить его из компонента формы и передать фактические данные в качестве реквизита после его получения - например, как @JakeSendar, предложенный в его ответе.

У меня есть опыт работы с изоморфным приложением с React, и главная проблема, с которой я столкнулся, - это подождать, пока все данные будут загружены до первого рендеринга

Как уже упоминалось в комментариях @FakeRainBrigand, есть только один способ сделать это, и это зависит от ваших требований.

Существует несколько способов создания изоморфного приложения, интересное с моей точки зрения: https://github.com/webpack/react-starter и http://fluxible.io/

Но самый элегантный способ сделать это, как я понял для себя, - организовать асинхронный рендеринг для реагирующих компонентов, в частности, с помощью RxJS.

В целом мое приложение структурировано следующим образом:

  • views - Реагировать на компоненты без какой-либо логики (просто представление)
  • - Наблюдаемые с текущим состоянием (исходные данные загружаются с использованием суперагента, затем объединены с другими моделями и/или результатами действий). В простом случае это что-то вроде:

    Rx.Observable.defer(fetchData).concat(updatesSubject).shareReplay()

  • действия (или намерения) - наблюдатели, используемые для сбора пользовательского ввода, выполнения чего-либо и отправки результатов действий для моделей подписчиков и/или других действий. В простом случае что-то вроде:

    updatesSubject = new Rx.Subject();

    action = new Rx.Subject(); action.switchMap(asyncRequest).subscribe(updatesSubject)

  • Компоненты - Observables (поток виртуальных элементов DOM), объединенный с моделями, другими компонентами и действиями (У меня есть примечание об этом, объясняя, как и зачем создавать элементы Observerable React с RxJS), теперь я планирую добавлять частичные компоненты (кортеж из: компонент реакции, наблюдаемые, наблюдатели и свойства, частично заполненные с использованием DI)

  • router - компонент, ответственный за обработку изменений местоположения, в основном основная особенность заключается в отображении изменений местоположения в поток виртуальных элементов DOM и метаинформации. Но в деталях, это немного сложнее в моем случае (генерация URL-адресов, активное выделение URL-адресов, обработка прокрутки при навигации, а также возможность вложенных маршрутов и несколько просмотров).

Все это собрано вместе с использованием контейнера DI, в моем случае, аналогичном angular2 контейнеру DI, но значительно упрощенному для моих конкретных потребностей.

Компоненты, модели и действия создаются с использованием DI.

На стороне сервера приложение выглядит следующим образом:

var rootInjector = new Injector();
// setup server specific providers
rootInjector.provide(..., ...)

app.get('/*', function(req,res){
    var injector = rootInjector.createChild();
    // setup request specific providers
    injector.provide(..., ...);

    injector.get(Router)
       .first()
       .subscribe(function(routingResult){ 
          res.render('app', {
              title: routingResult.title,
              content: React.renderToString(routingResult.content)
          });
       });
}

и аналогичные на стороне клиента:

var rootInjector = new Injector();
// setup server specific providers
// actually this is omitted in my case because default providers are client side
rootInjector.provide(..., ...)
contentElement = document.getElementById('#content');

rootInjector.get(Router)
   .subscribe(function(routingResult){ 
      document.title = routingResult.title;
      React.render(routingResult.content, contentElement)
   });

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

Скорее позже, я открою все это, но пока - он не совсем готов к публикации.

UPD1:

Оригинальный ответ немного устарел (позже я планирую его обновить), и у меня есть некоторый прогресс в этой области.

Ссылки на код, упомянутый выше, уже раскрыты:

  • контейнер DI: di1
  • Контейнер для реагирования компонентов (соединение с наблюдаемыми и общими): rx-react-container
  • Стартовый шаблон для реализации изоморфных виджетов с использованием RxJS и React и выше: Реактивные виджеты

О полном приложении (работа продолжается и документация там не очень хорошая, но в целом это должно быть понятно):

  • Маршрутизатор, созданный специально для изоморфных реактивных приложений router1 и реагирует на его компоненты router1-react
  • Шаблон приложения с маршрутизатором и всеми упомянутыми выше библиотеками: router1-app-template

Ответ 2

Реагировать renderToString метод (для рендеринга компонентов на сервере) является синхронным. Таким образом, любая задача async, такая как ваш запрос api, по-прежнему будет ожидаться к моменту, когда компонент предоставил.

Существует несколько способов исправить это, в зависимости от того, хотите ли вы получать данные на сервере или клиенте.

Если вы выбрали выборку данных на сервере, сначала переместите логику api-request вне своего компонента. Затем отрисуйте свой компонент в обратном вызове, передав извлеченные данные как prop. Это будет выглядеть примерно так:

response.on("end", function (err) {
  var data = JSON.parse(buffer);
  var markup = React.renderToString(Component({categories: data}));
});

Внутри вашего компонента вы сможете получить доступ к данным через this.props.categories.

Другой вариант - обработать запрос api на клиенте. Вы должны сделать запрос AJAX в componentDidMount и установить состояние компонента из извлеченных данных. Это будет выглядеть очень похоже на то, что у вас есть сейчас, главное отличие заключается в том, что ваша логика запроса будет жить в componentDidMount (async, вызываемая клиентом), а не componentWillMount (не асинхронная, вызываемая на сервере).

Ответ 3

Вы должны использовать superagent, отлично работает для меня, также вам не хватает самой важной части, вы должны использовать flux, чтобы получать данные с сервера, флюс - это то, что настоятельно рекомендуется facebook, довольно легко использовать флюсовую архитектуру.