Javascript 在 react js 中调用 API 的正确方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38742334/
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 21:47:43  来源:igfitidea点击:

what is right way to do API call in react js?

javascriptjqueryreactjs

提问by Raj Rj

I have recently moved from Angular to ReactJs. I am using jQuery for API calls. I have an API which returns a random user list that is to be printed in a list.

我最近从 Angular 转移到 ReactJs。我正在使用 jQuery 进行 API 调用。我有一个 API,它返回一个要打印在列表中的随机用户列表。

I am not sure how to write my API calls. What is best practice for this?

我不确定如何编写我的 API 调用。什么是最佳实践?

I tried the following but I am not getting any output. I am open to implementing alternative API libraries if necessary.

我尝试了以下操作,但没有得到任何输出。如有必要,我愿意实施替代 API 库。

Below is my code:

下面是我的代码:

import React from 'react';

export default class UserList extends React.Component {    
  constructor(props) {
    super(props);
    this.state = {
      person: []
    };
  }

  UserList(){
    return $.getJSON('https://randomuser.me/api/')
    .then(function(data) {
      return data.results;
    });
  }

  render() {
    this.UserList().then(function(res){
      this.state = {person: res};
    });
    return (
      <div id="layout-content" className="layout-content-wrapper">
        <div className="panel-list">
          {this.state.person.map((item, i) =>{
            return(
              <h1>{item.name.first}</h1>
              <span>{item.cell}, {item.email}</span>
            )
          })}
        <div>
      </div>
    )
  }
}

采纳答案by Alexander T.

In this case, you can do ajax call inside componentDidMount, and then update state

在这种情况下,你可以在里面做ajax调用componentDidMount,然后更新state

export default class UserList extends React.Component {
  constructor(props) {
    super(props);

    this.state = {person: []};
  }

  componentDidMount() {
    this.UserList();
  }

  UserList() {
    $.getJSON('https://randomuser.me/api/')
      .then(({ results }) => this.setState({ person: results }));
  }

  render() {
    const persons = this.state.person.map((item, i) => (
      <div>
        <h1>{ item.name.first }</h1>
        <span>{ item.cell }, { item.email }</span>
      </div>
    ));

    return (
      <div id="layout-content" className="layout-content-wrapper">
        <div className="panel-list">{ persons }</div>
      </div>
    );
  }
}

回答by Jei Trooper

You may want to check out the Flux Architecture. I also recommend checking out React-Redux Implementation. Put your api calls in your actions. It is much more cleaner than putting it all in the component.

您可能想查看Flux Architecture。我还建议查看React-Redux 实现。将您的 api 调用放在您的操作中。它比将所有内容都放在组件中要干净得多。

Actions are sort of helper methods that you can call to change your application state or do api calls.

Actions 是一种辅助方法,您可以调用它们来更改应用程序状态或执行 api 调用。

回答by love-for-coding

Use fetchmethod inside componentDidMountto update state:

使用fetch里面的方法componentDidMount来更新状态:

componentDidMount(){
  fetch('https://randomuser.me/api/')
      .then(({ results }) => this.setState({ person: results }));
}

回答by Devarsh Shah

I would like you to have a look at redux http://redux.js.org/index.html

我想让你看看 redux http://redux.js.org/index.html

They have very well defined way of handling async calls ie API calls, and instead of using jQuery for API calls, I would like to recommend using fetchor requestnpm packages, fetchis currently supported by modern browsers, but a shim is also available for server side.

他们有很好定义的方式来处理异步调用,即 API 调用,而不是使用 jQuery 进行 API 调用,我想推荐使用fetchrequestnpm 包,现代浏览器目前支持fetch,但也可以使用垫片服务器端。

There is also this another amazing package superagent, which has alot many options when making an API request and its very easy to use.

还有另一个惊人的包superagent,它在发出 API 请求时有很多选择,并且非常易于使用。

回答by Carr

This discussion has been for a while and @Alexander T.'s answer provided a good guide to follow for newer of React like me. And I'm gonna share some additional know-hows about calling the same API multiple times to refresh the component, I think it's probably a common problem that newbie may face at the beginning.

这个讨论已经有一段时间了,@Alexander T. 的回答为像我这样的 React 新手提供了一个很好的指导。我将分享一些关于多次调用相同 API 以刷新组件的额外知识,我认为这可能是新手一开始可能面临的常见问题。

componentWillReceiveProps(nextProps), from official documentation:

componentWillReceiveProps(nextProps),来自官方文档

If you need to update the state in response to prop changes (for example, to reset it), you may compare this.props and nextProps and perform state transitions using this.setState() in this method.

如果您需要更新状态以响应 prop 更改(例如,重置它),您可以比较 this.props 和 nextProps 并在此方法中使用 this.setState() 执行状态转换。

We could conclude that here is the place we handle props from the parent component, have API calls, and update state.

我们可以得出结论,这里是我们处理来自父组件的 props、API 调用和更新状态的地方。

Base on @Alexander T.'s example:

基于@Alexander T. 的例子:

export default class UserList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {person: []};
  }

  componentDidMount() {
   //For our first load. 
   this.UserList(this.props.group); //maybe something like "groupOne"
  }

  componentWillReceiveProps(nextProps) {
    // Assuming parameter comes from url.
    // let group = window.location.toString().split("/")[*indexParameterLocated*];
    // this.UserList(group);

    // Assuming parameter comes from props that from parent component.
    let group = nextProps.group; // Maybe something like "groupTwo" 
    this.UserList(group);
  }

  UserList(group) {
    $.getJSON('https://randomuser.me/api/' + group)
      .then(({ results }) => this.setState({ person: results }));
  }

  render() {
    return (...)
  }
}


Update

更新

componentWillReceiveProps()would be deprecated.

componentWillReceiveProps()将被弃用。

Here are only somemethods (all of them in Doc) in the life cycle which I think would be related to deploying API in general case: enter image description here

以下是生命周期中的一些方法(全部在Doc 中),我认为在一般情况下与部署 API 相关: 在此处输入图片说明

By referring the diagram above:

参考上图:

  • Deploy API incomponentDidMount()

    The proper scenario to have API call here is that the content (from the response of API) of this component will be static, componentDidMount()only fire once while the component is mounting, even new props are passed from parent component or have actions to lead re-rendering.
    The component do check difference to re-renderbut not re-mount.
    Quote from doc:

  • 部署 APIcomponentDidMount()

    此处调用 API 的正确场景是该组件的内容(来自 API 的响应)将是静态的,componentDidMount()仅在组件挂载时触发一次,即使是从父组件传递的新 props 或有操作引导re-rendering
    该组件会检查差异以重新渲染但不重新安装
    引用自doc

If you need to load data from a remote endpoint, this is a good place to instantiate the network request.

如果您需要从远程端点加载数据,这是实例化网络请求的好地方。



  • Deploy API instatic getDerivedStateFromProps(nextProps, prevState)
  • 部署 APIstatic getDerivedStateFromProps(nextProps, prevState)

We should notice that there are two kinds of component updating, setState()in current componentwould notlead this method to trigger, but re-rendering or new props from parent componentdo. We could found out that this method also fires while mounting.

我们应该注意到,有两种组件更新setState()在当前组件不会导致这种方法来触发,但重新渲染或新道具父组件做。我们可以发现这个方法在挂载时也会触发。

This is a proper place to deploy API if we want to use the current component like a template, and the new parameters for API are props coming from parent component.
We receive a different response from API and return a new statehere to change the content of this component.

如果我们想像模板一样使用当前组件,这是部署 API 的合适位置,并且 API 的新参数是来自父组件的 props
我们从 API 收到不同的响应,并state在此处返回一个新的以更改此组件的内容。

For example:
We have a dropdown list for different Cars in the parent component, this component needs to show the details of the selected one.

例如:
我们在父组件中有一个不同汽车的下拉列表,这个组件需要显示所选汽车的详细信息。



  • Deploy API incomponentDidUpdate(prevProps, prevState)
  • 部署 APIcomponentDidUpdate(prevProps, prevState)

Differ from static getDerivedStateFromProps(), this method is invoked immediately after every rendering except the initial rendering. We could have API calling and render difference in one component.

与 不同static getDerivedStateFromProps(),此方法在除初始渲染之外的每次渲染后立即调用。我们可以在一个组件中调用 API 并呈现差异。

Extend the previous example:
The component to show Car's details may contain a list of series of this car, if we want to check the 2013 production one, we may click or select or ... the list item to lead a first setState()to reflect this behavior (such as highlighting the list item) in this component, and in the following componentDidUpdate()we send our request with new parameters (state). After getting the response, we setState()again for rendering the different content of the Car details. To prevent the following componentDidUpdate()from causing the infinity loop, we need to compare the state by utilizing prevStateat the beginning of this method to decide if we send the API and render the new content.

扩展前面的例子:
显示Car的详细信息的组件可能包含这个汽车的系列列表,如果我们想查看2013年生产的一个,我们可以点击或选择或...列表项引导一个第一个setState()反映这一点此组件中的行为(例如突出显示列表项),接下来componentDidUpdate()我们发送带有新参数(状态)的请求。得到响应后,我们setState()再次对Car details的不同内容进行渲染。为了防止后面的componentDidUpdate()事情造成无限循环,我们需要通过prevState这个方法开始时的状态比较来决定是否发送API并渲染新的内容。

This method really could be utilized just like static getDerivedStateFromProps()with props, but need to handle the changes of propsby utilizing prevProps. And we need to cooperate with componentDidMount()to handle the initial API call.

这种方法确实可以像static getDerivedStateFromProps()props一样使用,但需要props通过使用prevProps. 并且我们需要配合componentDidMount()处理初始的 API 调用。

Quote from doc:

引用自doc

... This is also a good place to do network requests as long as you compare the current props to previous props ...

...这也是一个做网络请求的好地方,只要你比较当前的 props 和之前的 props ...

回答by Alireza

This part from React v16documentation will answer your question, read on about componentDidMount():

React v16文档中的这一部分将回答您的问题,请继续阅读有关 componentDidMount() 的内容:

componentDidMount()

componentDidMount() is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request. This method is a good place to set up any subscriptions. If you do that, don't forget to unsubscribe in componentWillUnmount().

组件DidMount()

componentDidMount() 在组件安装后立即调用。需要 DOM 节点的初始化应该在这里进行。如果您需要从远程端点加载数据,这是实例化网络请求的好地方。此方法是设置任何订阅的好地方。如果这样做,请不要忘记在 componentWillUnmount() 中取消订阅。

As you see, componentDidMountis considered the best place and cycle to do the api call, also access the node, means by this time it's safe to do the call, update the view or whatever you could do when document is ready, if you are using jQuery, it should somehow remind you document.ready() function, where you could make sure everything is ready for whatever you want to do in your code...

如您所见,componentDidMount被认为是执行api 调用的最佳位置和循环,也可以访问节点,这意味着此时可以安全地进行调用、更新视图或文档准备就绪时可以执行的任何操作,如果您是使用 jQuery,它应该以某种方式提醒您 document.ready() 函数,您可以在其中确保一切准备就绪,可以在代码中执行任何操作...

回答by Nhan Tran

Render function should be pure, it's mean that it only uses state and props to render, never try to modify the state in render, this usually causes ugly bugs and decreases performance significantly. It's also a good point if you separate data-fetching and render concerns in your React App. I recommend you read this article which explains this idea very well. https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm

Render 函数应该是纯的,这意味着它只使用 state 和 props 来渲染,永远不要尝试修改渲染中的状态,这通常会导致丑陋的错误并显着降低性能。如果您将 React 应用程序中的数据获取和渲染关注点分开,这也是一个好点。我建议你阅读这篇文章,它很好地解释了这个想法。https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm

回答by Hitesh Sahu

1) You can use Fetch APIto fetch data from Endd Points:

1) 您可以使用 F etch API从端点获取数据:

Example fetching all Githubrepose for a user

Github为用户获取所有休息的示例

  /* Fetch GitHub Repos */
  fetchData = () => {

       //show progress bar
      this.setState({ isLoading: true });

      //fetch repos
      fetch(`https://api.github.com/users/hiteshsahu/repos`)
      .then(response => response.json())
      .then(data => {
        if (Array.isArray(data)) {
          console.log(JSON.stringify(data));
          this.setState({ repos: data ,
                         isLoading: false});
        } else {
          this.setState({ repos: [],
                          isLoading: false  
                        });
        }
      });
  };

2) Other Alternative is Axios

2) 其他替代方案是Axios

Using axios you can cut out the middle step of passing the results of the http request to the .json() method. Axios just returns the data object you would expect.

使用 axios,您可以省去将 http 请求的结果传递给 .json() 方法的中间步骤。Axios 只返回您期望的数据对象。

  import axios from "axios";

 /* Fetch GitHub Repos */
  fetchDataWithAxios = () => {

     //show progress bar
      this.setState({ isLoading: true });

      // fetch repos with axios
      axios
          .get(`https://api.github.com/users/hiteshsahu/repos`)
          .then(result => {
            console.log(result);
            this.setState({
              repos: result.data,
              isLoading: false
            });
          })
          .catch(error =>
            this.setState({
              error,
              isLoading: false
            })
          );
}

Now you can choose to fetch data using any of this strategies in componentDidMount

现在您可以选择使用以下任何一种策略来获取数据 componentDidMount

class App extends React.Component {
  state = {
    repos: [],
   isLoading: false
  };

  componentDidMount() {
    this.fetchData ();
  }

Meanwhile you can show progress bar while data is loading

同时您可以在数据加载时显示进度条

   {this.state.isLoading && <LinearProgress />}

回答by iamnotsam

You can also fetch data with hooksin your function components

您还可以使用函数组件中的钩子获取数据

full example with api call: https://codesandbox.io/s/jvvkoo8pq3

api 调用的完整示例:https: //codesandbox.io/s/jvvkoo8pq3

second example: https://jsfiddle.net/bradcypert/jhrt40yv/6/

第二个例子:https: //jsfiddle.net/bradcypert/jhrt40yv/6/

const Repos = ({user}) => {
  const [repos, setRepos] = React.useState([]);

  React.useEffect(() => {
    const fetchData = async () => {
        const response = await axios.get(`https://api.github.com/users/${user}/repos`);
        setRepos(response.data);
    }

    fetchData();
  }, []);

  return (
  <div>
    {repos.map(repo =>
      <div key={repo.id}>{repo.name}</div>
    )}
  </div>
  );
}

ReactDOM.render(<Repos user="bradcypert" />, document.querySelector("#app"))

回答by Tania Shulga

A clean way is to make an asynchronous API call inside componentDidMountwith try/catch function.

一种干净的方法是使用try/catch 函数componentDidMount内部进行异步 API 调用。

When we called an API, we receive a response. Then we apply JSON method on it, to convert the response into a JavaScript object. Then we take from that response object only his child object named "results" (data.results).

当我们调用 API 时,我们会收到响应。然后我们对其应用 JSON 方法,将响应转换为 JavaScript 对象。然后我们从那个响应对象中只取他名为“results”(data.results)的子对象。

In the beginning we defined "userList" in state as an empty array. As soon as we make the API call and receive data from that API, we assign the "results" to userList using setState method.

一开始我们将 state 中的“userList”定义为一个空数组。一旦我们调用 API 并从该 API 接收数据,我们就会使用setState 方法将“结果”分配给 userList 。

Inside the render function we tell that userList will be coming from state. Since the userList is an array of objects we map through it, to display a picture, a name and a phone number of each object "user". To retrieve this information we use dot notation (e.g. user.phone).

在渲染函数中,我们告诉 userList 将来自状态。由于 userList 是我们通过它映射的对象数组,以显示每个对象“用户”的图片、姓名和电话号码。为了检索这些信息,我们使用点符号(例如 user.phone)。

NOTE: depending on your API, your response may look different. Console.log the whole "response" to see which variables you need from it, and then assign them in setState.

注意:根据您的 API,您的响应可能看起来不同。Console.log 整个“响应”以查看您需要从中获取哪些变量,然后在 setState 中分配它们。

UserList.js

用户列表.js

import React, { Component } from "react";

export default class UserList extends Component {
   state = {
      userList: [], // list is empty in the beginning
      error: false
   };

   componentDidMount() {
       this.getUserList(); // function call
   }

   getUserList = async () => {
       try { //try to get data
           const response = await fetch("https://randomuser.me/api/");
           if (response.ok) { // ckeck if status code is 200
               const data = await response.json();
               this.setState({ userList: data.results});
           } else { this.setState({ error: true }) }
       } catch (e) { //code will jump here if there is a network problem
   this.setState({ error: true });
  }
};

  render() {
  const { userList, error } = this.state
      return (
          <div>
            {userList.length > 0 && userList.map(user => (
              <div key={user}>
                  <img src={user.picture.medium} alt="user"/>
                  <div>
                      <div>{user.name.first}{user.name.last}</div>
                      <div>{user.phone}</div>
                      <div>{user.email}</div>
                  </div>
              </div>
            ))}
            {error && <div>Sorry, can not display the data</div>}
          </div>
      )
}}