我最近从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>
)
}
}
答案 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有关:
参考上图:
在 componentDidMount()
这里有API调用的正确方案是该组件的内容(来自API的响应)将是静态的,componentDidMount()
仅在组件安装时触发一次,甚至从父组件传递新的道具或采取行动领导re-rendering
该组件会检查差异为重新渲染,但不会重新安装。
引自doc:
如果您需要从远程端点加载数据,这是一个好地方 实例化网络请求。
static getDerivedStateFromProps(nextProps, prevState)
我们应该注意到组件更新有两种,当前组件中的setState()
会不将此方法引导至触发,但重新渲染或来自父组件的新道具。
我们可以发现这种方法在安装时也会发射。
如果我们想要像模板那样使用当前组件,那么这是部署API 的合适位置,而API的新参数是来自父组件的道具。
我们从API收到不同的响应,并在此处返回新的state
以更改此组件的内容。
例如:
我们有一个父组件中不同汽车的下拉列表,该组件需要显示所选汽车组件的详细信息。
componentDidUpdate(prevProps, prevState)
与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
中。例如:
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
进一步阅读: