Javascript 从react js进行宁静的api调用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29935827/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:20:41  来源:igfitidea点击:

making restful api call from react js

javascriptreactjsisomorphic-javascript

提问by kobe

I am doing a POC for isomorphic javascript application to render html from the server side. The POC is working with simple html, but I want to make an api call and get the json response and send to the render function. I tried various ways but it is not working. Can one of you please let me know where I am missing.

我正在为同构 javascript 应用程序做一个 POC,以从服务器端呈现 html。POC 使用简单的 html,但我想进行 api 调用并获取 json 响应并发送到渲染函数。我尝试了各种方法,但它不起作用。你们中的一个人可以让我知道我失踪的地方。

I am very new to react js and any help will be really appreciated

我对反应 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>
        )
      }

  });

回答by Bogdan Savluk

Fetching inside of component using componentWillMountis not a right place, in case when you need to render server side. You need to somehow move it out form component, and pass actual data as props after it is fetched - for example as @JakeSendar suggested in his answer.

componentWillMount在需要渲染服务器端的情况下,使用获取组件内部不是一个正确的地方。您需要以某种方式将其移出表单组件,并在获取后将实际数据作为道具传递 - 例如@JakeSendar 在他的回答中建议。

I have some experience doing isomorphic app with React, and the main problem I faced is how to wait until all data would be loaded before first render

我有一些使用 React 做同构应用程序的经验,我面临的主要问题是如何在第一次渲染之前等待所有数据都加载完毕

As @FakeRainBrigand already mentioned in comments, there is not only one way to do this, and it depends from your requirements.

正如@FakeRainBrigand 已经在评论中提到的那样,不仅有一种方法可以做到这一点,这取决于您的要求。

There is few ways to do build an isomorphic app, the some interesting from my perspective is: https://github.com/webpack/react-starterand http://fluxible.io/

构建同构应用程序的方法很少,从我的角度来看,一些有趣的是:https: //github.com/webpack/react-starterhttp://fluxible.io/

But, the most elegant way to do this, as I figured out for myself - is to organise asynchronous rendering for react components, in particular using RxJS.

但是,正如我自己发现的那样,最优雅的方法是为 React 组件组织异步渲染,尤其是使用 RxJS。

In general my application is structured as following:

一般来说,我的应用程序结构如下:

  1. views - React components without any logic (just a view)
  2. models - Observables with current state (initial data is loaded using superagent, then combined with other models and/or actions results). In simple case it is something like:

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

  3. actions(or intents) - Observers used to collects user input, do something, and dispatch action results to subscribers models and/or other actions. In simple case something like:

    updatesSubject = new Rx.Subject();

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

  4. components - Observables(stream of virtual DOM elements) combined from models, other components and actions (I have a note about this, explaining how and why to create Observable React elements with RxJS), also now I am planning to add partial components (tuple from: react component, observables, observers, and properties. partially filled with using DI)

  5. router - component responsible to handling location changes, in general main feature is to map location changes to stream of virtual DOM elements and meta information. But in details, it is bit more complicated in my case(url generation, active url highlighting, handling scrolls when navigating, also it has possibility of nested routes and multiple views)

  1. 视图 - 没有任何逻辑的反应组件(只是一个视图)
  2. 模型 - 当前状态的 Observables(使用超级代理加载初始数据,然后与其他模型和/或操作结果结合)。在简单的情况下,它类似于:

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

  3. 动作(或意图) - 用于收集用户输入、执行某些操作并将动作结果分发给订阅者模型和/或其他动作的观察者。在简单的情况下,例如:

    updatesSubject = new Rx.Subject();

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

  4. 组件 - 由模型、其他组件和动作组合而成的 Observables(虚拟 DOM 元素流)(我对此有一个注释,解释了如何以及为什么使用 RxJS 创建 Observable React 元素),现在我也计划添加部分组件(元组来自:反应组件、可观察对象、观察者和属性。部分填充了使用 DI)

  5. 路由器 - 负责处理位置更改的组件,通常主要功能是将位置更改映射到虚拟 DOM 元素和元信息流。但在细节上,在我的情况下有点复杂(网址生成,活动网址突出显示,导航时处理滚动,还有嵌套路由和多个视图的可能性)

All this is assembled together using DI container, in my case similar to angular2 DI container, but a lot simplified for my specific needs.

所有这些都是使用 DI 容器组装在一起的,在我的情况下类似于angular2 DI container,但针对我的特定需求进行了很多简化。

Components, models and actions are created using DI.

组件、模型和动作是使用 DI 创建的。

On server side application is like this:

在服务器端应用程序是这样的:

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

and similar on client side:

和客户端类似:

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

In comparison to flux, it is more declarative and more powerful way to organise app. And in case of isomorphic app - for me, it looks much better that various hacks with flux. But of course there is drawbacks... - it is more complicated.

与flux相比,它是一种更具声明性和更强大的组织应用程序的方式。对于同构应用程序 - 对我来说,使用流量进行各种黑客攻击看起来要好得多。但是当然有缺点...... - 它更复杂。

Likely later, I will opensource all this, but for now - it is not quite ready to be published.

可能稍后,我会将所有这些开源,但就目前而言 - 它尚未准备好发布。

UPD1:

UPD1:

Original answer is a bit outdated(later I plan to update it), and I have some progress in this area.

原答案有点过时了(以后打算更新),我在这方面有一些进展。

Links to code mentioned above, already opensourced:

上面提到的代码链接,已经开源:

  • DI container: di1
  • Container for react componentns(connecting view to observables and obsrvers): rx-react-container
  • Starter template, for implementing isomorphic widgets, using RxJS and React, and libraries above: Reactive Widgets
  • DI容器:di1
  • 反应组件的容器(将视图连接到 observables 和 obrvers):rx-react-container
  • 入门模板,用于实现同构小部件,使用 RxJS 和 React,以及上面的库:Reactive Widgets

About complete application(work still in progress, and documentation there is not quite good, but in general it should be clear):

关于完整的应用程序(工作仍在进行中,文档不是很好,但总的来说应该很清楚):

回答by Jake Sendar

React's renderToStringmethod (for rendering components on the server) is synchronous. Therefore, any sort of async task, such as your api request, will still be pending by the time the component has rendered.

React 的renderToString方法(用于在服务器上渲染组件)是同步的。因此,任何类型的异步任务,例如您的 api 请求,在组件呈现时仍将处于挂起状态。

There are a couple of ways you can go about fixing this, depending on whether or not you want to fetch your data on the server or client.

有几种方法可以解决此问题,具体取决于您是要在服务器还是客户端上获取数据。

If you choose to fetch the data on the server, first move your api-request logic outside of your component. Then, render your component in the callback, passing the fetched-data as a prop. It would look something like this:

如果您选择在服务器上获取数据,请首先将您的 api 请求逻辑移到您的组件之外。然后,在回调中呈现您的组件,将获取的数据作为prop. 它看起来像这样:

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

Inside your component, you'd be able to access the data via this.props.categories.

在您的组件中,您可以通过this.props.categories.

The other option is to handle the api request on the client. You would make an AJAX request in componentDidMount, and set the component's state from the fetched data. It would look very similar to what you have now, the key difference being that your request logic would live in componentDidMount(async, called on the client) rather than componentWillMount(not async, called on the server).

另一种选择是在客户端处理 api 请求。您将在 中发出 AJAX 请求componentDidMount,并根据获取的数据设置组件的状态。它看起来与您现在拥有的非常相似,主要区别在于您的请求逻辑将存在于componentDidMount(异步,在客户端调用)而不是componentWillMount(非异步,在服务器上调用)。

回答by David Eduardo Ortiz Velasco

You should use superagent, works really good for me, also you are missing the most important part, you should use fluxto fetch data from a server, flux is the way that facebook strongly recommended, it's pretty easy to use flux architecture.

你应该使用superagent,对我来说真的很好,而且你也错过了最重要的部分,你应该使用flux从服务器获取数据,flux是facebook强烈推荐的方式,使用flux架构非常容易。