写在最前面
- 适用于 react 初学者,需要了解怎么优雅的处理获取数据操作。
- loading 和 error 逻辑怎么处理?
- 使用 Promises 和 Async/Await, 高阶组件获取数据?
怎么优雅的使用 react 获取数据
- 普通刚开始学习 react 的初学者都会有一个问题,我们需要展示一列数据。但是我们需要在 react 的生命周期(lifecycle)中哪里去获取这个数据合适啦?
- 现在我们知道
componentDidMount
在生命周期中
使用 JavaScript Promises 去处理数据
- 在
componentDidMount()
使用promise
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: null,
};
}
componentDidMount() {
fetch('https://api.mydomain.com')
.then(response => response.json())
.then(data => this.setState({ data }));
}
...
}
export default App;
复制代码
当然我们可以使用第三方 api,当我们获取数据成功以后。然后就被存储到了 react 的
this.setState()
方法中。然后render()
会重新渲染,然后我们就可以看到我们的数据展示了。
...
class App extends Component {
...
render() {
const { hits } = this.state;
return (
<ul>
{hits.map(hit =>
<li key={hit.objectID}>
<a href={hit.url}>{hit.title}</a>
</li>
)}
</ul>
);
}
}
export default App;
复制代码
note: 如果你想了解最新的 react hooks 来获取处理数据的方法:www.robinwieruch.de/react-hooks…
怎么优雅的处理 loading 和 error?
- 一般在获取数据的时候我们需要处理几种情况,加载中 loading,出错 error,加载成功。所以一般情况下我们会把 loading 和 error 状态存在 state 中。
loading 加载中处理
...
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
isLoading: false,
};
}
componentDidMount() {
this.setState({ isLoading: true });
fetch(API + DEFAULT_QUERY)
.then(response => response.json())
.then(data => this.setState({ hits: data.hits, isLoading: false }));
}
...
}
export default App;
复制代码
- 使用一个 Loading 的提示
...
class App extends Component {
...
render() {
const { hits, isLoading } = this.state;
if (isLoading) {
return <p>Loading ...</p>;
}
return (
<ul>
{hits.map(hit =>
<li key={hit.objectID}>
<a href={hit.url}>{hit.title}</a>
</li>
)}
</ul>
);
}
}
复制代码
Error 处理
- 初始化 error
...
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
isLoading: false,
error: null,
};
}
...
}
复制代码
- 当我们使用
promise
的使用,使用catch()
去捕捉错误。
...
class App extends Component {
...
componentDidMount() {
this.setState({ isLoading: true });
fetch(API + DEFAULT_QUERY)
.then(response => response.json())
.then(data => this.setState({ hits: data.hits, isLoading: false }))
.catch(error => this.setState({ error, isLoading: false }));
}
...
}
复制代码
- react 原生的API 不能处理一些错误的状态码,这里需要手动处理一下。
...
class App extends Component {
...
componentDidMount() {
this.setState({ isLoading: true });
fetch(API + DEFAULT_QUERY)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong ...');
}
})
.then(data => this.setState({ hits: data.hits, isLoading: false }))
.catch(error => this.setState({ error, isLoading: false }));
}
...
}
复制代码
- 当然,我们完全可以展示错误提示。
...
class App extends Component {
...
render() {
const { hits, isLoading, error } = this.state;
if (error) {
return <p>{error.message}</p>;
}
if (isLoading) {
return <p>Loading ...</p>;
}
return (
<ul>
{hits.map(hit =>
<li key={hit.objectID}>
<a href={hit.url}>{hit.title}</a>
</li>
)}
</ul>
);
}
}
复制代码
使用 Axios 来获取数据
import React, { Component } from 'react';
import axios from 'axios';
const API = 'https://hn.algolia.com/api/v1/search?query=';
const DEFAULT_QUERY = 'redux';
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
isLoading: false,
error: null,
};
}
componentDidMount() {
this.setState({ isLoading: true });
axios.get(API + DEFAULT_QUERY)
.then(result => this.setState({
hits: result.data.hits,
isLoading: false
}))
.catch(error => this.setState({
error,
isLoading: false
}));
}
...
}
export default App;
复制代码
使用 Async/Await 来获取数据
import React, { Component } from 'react';
import axios from 'axios';
const API = 'https://hn.algolia.com/api/v1/search?query=';
const DEFAULT_QUERY = 'redux';
class App extends Component {
...
async componentDidMount() {
this.setState({ isLoading: true });
try {
const result = await axios.get(API + DEFAULT_QUERY);
this.setState({
hits: result.data.hits,
isLoading: false
});
} catch (error) {
this.setState({
error,
isLoading: false
});
}
}
...
}
export default App;
复制代码
使用 高阶组件来获取数据
- 不明白高阶组件的同学可以看看我以前的文章: juejin.im/post/5c0f6e…
const withFetching = (url) => (Component) =>
class WithFetching extends React.Component {
constructor(props) {
super(props);
this.state = {
data: null,
isLoading: false,
error: null,
};
}
componentDidMount() {
this.setState({ isLoading: true });
axios.get(url)
.then(result => this.setState({
data: result.data,
isLoading: false
}))
.catch(error => this.setState({
error,
isLoading: false
}));
}
render() {
return <Component { ...this.props } { ...this.state } />;
}
}
复制代码
- 怎么使用
const withFetching = (url, query) => (Comp) =>
...
复制代码