什么是在反应js中进行API调用的正确方法?

时间:2016-08-03 11:30:17

标签: javascript jquery reactjs

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

我不确定如何编写API调用。这是什么最佳做法?

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

以下是我的代码:

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

14 个答案:

答案 0 :(得分:79)

在这种情况下,您可以在componentDidMount内进行ajax调用,然后更新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>
    );
  }
}

答案 1 :(得分:22)

您可能想查看Flux Architecture。我还建议您查看React-Redux Implementation。把api电话放在你的行动中。它比把它全部放在组件中更清洁。

操作是一种辅助方法,您可以调用它们来更改应用程序状态或进行API调用。

答案 2 :(得分:10)

我希望你看看redux http://redux.js.org/index.html

他们有非常明确的处理异步调用的方式,即API调用,而不是使用jQuery进行API调用,我建议使用获取请求 npm现代浏览器目前支持包 fetch ,但服务器端也可以使用垫片。

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

答案 3 :(得分:10)

fetch中使用componentDidMount方法更新状态。如下所示

...

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

...

答案 4 :(得分:6)

这个讨论已经有一段时间了,@亚历山大T的答案提供了一个很好的指导,可以跟随像我这样的反应。而且我将分享额外的知识如何进行讨论,以解决新手在开始时可能面临的一个常见问题。

来自official documentation

componentWillReceiveProps(nextProps)

  

如果你需要更新状态以响应道具变化(for   例如,重置它),你可以比较this.props和nextProps和   在此方法中使用this.setState()执行状态转换。

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

基于@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 (...)
  }
}

更新

componentWillReceiveProps()将被弃用。

在生命周期中,这里只有一些方法(所有这些方法都在Doc中),我认为这与在一般情况下部署API有关: enter image description here

参考上图:

  • componentDidMount()

    中部署API

    这里有API调用的正确方案是该组件的内容(来自API的响应)将是静态的,componentDidMount()仅在组件安装时触发一次,甚至从父组件传递新的道具或采取行动领导re-rendering 该组件会检查差异为重新渲染,但不会重新安装
    引自doc

  

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

  • static getDerivedStateFromProps(nextProps, prevState)
  • 中部署API

我们应该注意到组件更新有两种,当前组件中的setState() 将此方法引导至触发,但重新渲染或来自父组件的新道具。 我们可以发现这种方法在安装时也会发射。

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

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

  • componentDidUpdate(prevProps, prevState)
  • 中部署API

static getDerivedStateFromProps()不同,除了初始渲染之外,每次渲染后都会立即调用此方法。我们可以在一个组件中进行API调用和渲染差异。

扩展前一个例子:
显示Car的详细信息的组件可能包含此车系列的列表,如果我们要查看2013年的生产,我们可以点击或选择或......列出项目以引导第一个{{1}在这个组件中反映这种行为(例如突出显示列表项),在下面的setState()中,我们使用新参数(state)发送请求。收到回复后,我们再次componentDidUpdate()呈现Car详细信息的不同内容。为防止以下setState()导致无限循环,我们需要在此方法开头使用componentDidUpdate()来比较状态,以决定是否发送API并呈现新内容。

这种方法实际上可以像prevState一样使用道具,但需要使用static getDerivedStateFromProps()来处理props的更改。我们需要与prevProps合作处理初始API调用。

引自doc

  

...只要你这也是做网络请求的好地方   将当前道具与以前的道具进行比较......

答案 5 :(得分:3)

渲染函数应该是纯粹的,它意味着它只使用状态和道具进行渲染,从不尝试修改渲染中的状态,这通常会导致丑陋的错误并显着降低性能。如果您在React App中分离数据获取和渲染问题,这也是一个很好的观点。我建议你阅读这篇文章,它很好地解释了这个想法。 https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm

答案 6 :(得分:3)

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

  

componentDidMount()

     

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

如您所见, componentDidMount 被认为是进行 api调用的最佳位置和周期,同时也访问节点,这意味着此时它是安全的进行调用,更新视图或文档准备就绪时可以做的任何事情,如果你使用jQuery,它应该以某种方式提醒你document.ready()函数,你可以确保一切都准备好你想做什么在你的代码......

答案 7 :(得分:2)

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

为用户获取所有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)其他选择是 Axios

  

使用axios,您可以省去传递结果的中间步骤   .json()方法的http请求。 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
            })
          );
}

现在,您可以在componentDidMount

中选择使用任何一种策略来获取数据
class App extends React.Component {
  state = {
    repos: [],
   isLoading: false
  };

  componentDidMount() {
    this.fetchData ();
  }

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

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

答案 8 :(得分:2)

您也可以在功能组件中fetch data with hooks

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

第二个示例: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"))

答案 9 :(得分:0)

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

当我们调用API时,我们会收到响应。然后,我们对其应用JSON方法,以将响应转换为JavaScript对象。然后,我们从该响应对象中仅获取其子对象“ results”(data.results)。

首先,我们将状态为“ userList”的状态定义为一个空数组。调用API并从该API接收数据后,我们便使用 setState方法将“结果”分配给userList。

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

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

UserList.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>
      )
}}

答案 10 :(得分:0)

React Lifecycle方法 componentDidMount()是外部API调用的最佳位置和做法,在执行API调用后,您应更新本地状态以触发新的 render( )方法调用,则更新后的本地状态中的更改将应用​​于组件视图。

作为React中用于初始外部数据源调用的其他选项,指向该类的 constructor()方法。构造函数是在初始化组件对象实例时执行的第一个方法。您可以在Higher-Order Components的文档示例中看到这种方法。

方法 componentWillMount() UNSAFE_componentWillMount()不应用于外部API调用,因为它们已被弃用。 Here,您会看到常见的原因,为何不赞成使用此方法。

无论如何,您都必须不要使用render()方法或直接从render()直接调用的方法作为外部API调用的点。如果这样做,您的应用程序将被阻止

答案 11 :(得分:0)

只需在此处添加当前ALTER TABLE mysql.user DROP COLUMN is_role; 可能是现在放置api调用的地方。 参见https://btholt.github.io/complete-intro-to-react-v5/effects

答案 12 :(得分:0)

将axios用于支持取消,拦截器等的api请求会很棒。与axios一起,我将react-redux用于状态管理,并将redux-saga / redux-thunk用于副作用。

答案 13 :(得分:0)

作为对 Oleksandr T. 出色回答的补充/更新:

  • 如果您使用类组件,后端调用应该发生在 componentDidMount 中。
  • 如果您使用 hooks,则应使用 effect hook

例如:

import React, { useState, useEffect } from 'react';
   
useEffect(() => {
   fetchDataFromBackend();
}, []);

// define fetchDataFromBackend() as usual, using Fetch API or similar;
// the result will typically be stored as component state

进一步阅读: