在js中做API调用的正确方法是什么?
我最近从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> ) } }
在这种情况下,您可以在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> ); } }
你可能想看看Flux Architecture 。 我也推荐检查React-Redux实现 。 把你的API调用放在你的行为中。 比把它放在组件中要干净得多。
动作是一些辅助方法,您可以调用它来更改应用程序状态或执行api调用。
我希望你能看看REDUX http://redux.js.org/index.html
他们有非常明确的方式来处理asynchronous调用,即API调用,而不是使用jQuery的API调用,我想推荐使用获取或请求 npm包, fetch目前支持现代浏览器,但垫片也可用于服务器端。
还有另一个惊人的包superagent ,它提出了API请求,有很多select,它非常容易使用。
渲染函数应该是纯粹的,这意味着它只使用状态和道具来渲染,从不尝试修改其中的状态,这通常会导致丑陋的错误,并显着降低性能。 如果您将数据提取和渲染问题分离到您的React App中,这也是一个好的方面。 我build议你阅读这篇文章,很好地解释这个想法。 https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm
这个讨论已经有一段时间了,@Alexander T.的答案提供了一个很好的约定,以跟随像我这样刚刚做出反应的人。 现在我要分享一些额外的知识,讨论新手可能面临的一个常见问题。
在我们有像模板一样使用组件的情况下。 我们希望目前的刷新取决于API调用的不同参数。 我们可能会发现,我们部署API调用的componentDidMount()
只会在第一次加载时触发一次。 不pipe怎样我们通过setState()来更改状态,它将不会再被触发。 实际上, setState()
只是让render()
函数重新渲染。 而且这也提醒我们,我们不能让setState()
只和render()
组件渲染相关render()
关于这个问题有很多讨论,导致无穷循环),所以API调用也不能在这里部署。
我们在这种情况下需要的是来自官方文档的函数componentWillReceiveProps(nextProps)
:
如果您需要更新状态以响应prop更改(例如,重置它),则可以比较this.props和nextProps,并使用this.setState()在此方法中执行状态转换。
我们可以得出结论,这里是我们处理我们的参数的地方,它可能来自父组件的url或者道具,有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() { 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> ); } }