在 React 应用中获取数据

640?wx_fmt=jpeg

可以说 React 是构建 web 应用最流行的库。然而,它并不是全能的 web 框架。它只关注 MVC 中的 view 模块。


React 整个生态系统可以解决其它问题。这篇教程中,你将会学到如何在 React web 应用中获取数据并显示。这很重要。 在整个 React 组件中有几个地方都可以获取远程数据。何时获取数据是另外一个问题。你还需要考虑用何种技术获取数据、数据存储在哪里。


在教程结束后,你会清楚的知道 React 中该如何获取数据,不同方法的利弊和如何在 React 应用中使用这些技术。

640?wx_fmt=png

开始

640?wx_fmt=png

让我们用 create-react-app 创建一个 React 应用的框架:

> create-react-app react-data-fetcher

我们会得到一个精致的结构目录。如果,你不熟悉 create-react-app,可以先看看 README 文件。

640?wx_fmt=png

创建简单的服务

640?wx_fmt=png

我创建了一个简单的 quotes 服务。这篇教程的重点不是它,它可以提供远程 API 用来演示如何在 React 中获取数据。 为了满足你们的好奇心,它是一个基于 hug 框架 (http://www.hug.rest/)Python 3 的应用,用 Redis 做持久化存储。


API 非常简单。/quotes 是一个简单接口。通过一个 GET 请求返回所有的 quotes,并且你可以通过 POST 请求新增一条记录。


完整的代码可以在 GitHub (https://github.com/the-gigi/quote-service)查看。

640?wx_fmt=png

App 预览

640?wx_fmt=png

这个 React 应用 Demo 可以和 quote 服务通信、显示所有的 quote 并可以添加新的记录。


这是截图:

640?wx_fmt=png

App 的结构非常简单。我用 create-react-app 创建了一个基础框架并在 src 目录中添加两个组件:QuoteList 和 AddQuoteForm。以下是详细的目录结构(不包含 node_moudules):

640?wx_fmt=png 640?wx_fmt=png 640?wx_fmt=png

QuoteList 函数组件以无序列表的形式展示所有的 quotes。它需要传入一组数据字符串:

import React from 'react'
const QuoteList = ({quotes}) =>
quotes.map(quote => <li key={quote}>{quote}</li>)
export default QuoteList
640?wx_fmt=png 640?wx_fmt=png

Fetch 是基于 promise 的 API,它会返回一个对象。为了得到实际的 JSON 数据,你需要对响应对象执行 json() 方法。

fetchQuotes = () => {
this.setState({...this.state, isFetching: true})
fetch(QUOTE_SERVICE_URL)
.then(response => response.json())
.then(result => this.setState({quotes: result,
isFetching: false}))
.catch(e => console.log(e));}
}
640?wx_fmt=png 640?wx_fmt=png

当然 React 都是组件。重点是何时何地才去加载获取远程数据呢! 如果你能很好的组织代码,你应该会有很多的通用组件和一些特定的组件。React 和 JavaScript 通常非常灵活,你可以在任何地方注入业务逻辑。


因为我希望数据一直是最新的,所以,会以轮询的方式通过 REST API 获取远程数据。 但是,初始化数据也非常重要。React 组件的生命周期方法允许你在特定的时间执行你需要的业务逻辑。 componentDidMount()方法会在组件可访问的时候执行,此时就可以改变组件的 state。这时候获取远程数据是非常合适的。


看起来就像这样:

componentDidMount() {
this.fetchQuotes()
}

如果,你想缩短页面的第一次可见的时间,你可以考虑在 componentWillMount() 方法中初始化异步数据,但是,这有可能会在组件未装载前完成数据请求。我不推荐这么操作。

640?wx_fmt=png 640?wx_fmt=png

在 componentDidMount() 方法中初始化数据是很合理的,但是,我需要经常更新数据。基于 REST API,只有通过轮询的方式解决。Quote 服务器非常简单,而且始终都会返回所有的 quotes。


大多数可扩展服务都会提供方法检查 HTTP 中的 if-modify-since 和 eTag 判断数据是否有更新。我们的应用中只是在 componentDidMount() 方法中启动一个 5s 的定时器更新数据,然后,在 componentWillUnmount() 方法清除定时器

componentDidMount() {
this.fetchQuotes()
this.timer = setInterval(() => this.fetchQuotes(), 5000);
}
componentWillUnmount() {
this.timer = null;
}

轮询的时间间隔由应用决定。如果,你需要实时更新,并后台有性能要求,可以考虑用 WebSockets 代替 REST。

640?wx_fmt=png 640?wx_fmt=png

有时候加载数据会花费很长时间。在这种下,显示一个进度条或者一个醒目的动画让用户知道程序正在处理,这对用户体验有很大的帮助。 当用户在初始化数据的时候(比如:点击搜索按钮)这很重要。


在演示 app 中,当请求时数据时我简单的显示一条提示信息:“请求数据中...”。在 App 组件的 render() 方法中,通过检查state.isFetching 的值来决定是否显示提示信息。

render() {
const title = 'Quotes for ya!'
   let now = new Date()
return (
<div className='App'>
<h2 className='App-title'>{title}</h2>
<p>{this.state.isFetching ? 'Fetching quotes...' : ''}</p>
<QuoteList quotes={this.state.quotes} />
<AddQuoteForm quote_service_url={QUOTE_SERVICE_URL}/>
</div>
);
}

fetchQuotes() 方法在初始化开始的时候会把 state.isFetching 的值更新为 true,当有响应返回的时候就切换回 false:

 fetchQuotes = () => {


this.setState({...this.state, isFetching: true})
fetch(QUOTE_SERVICE_URL)
.then(response => response.json())
.then(result => this.setState({quotes: result,
isFetching: false}))
.catch(e => console.log(e));
}
640?wx_fmt=png 640?wx_fmt=png

在这里我对错误的处理非常有限只是捕获错误并输出到控制台。在你的应用中,你可以执行一些重试逻辑、提示用户或者显示一些预设的内容。

640?wx_fmt=png 640?wx_fmt=png

Fetch API 是有缺陷的。处理响应的时候必须额外的经过 JSON 处理。它也不会捕获所有的错误。 例如,404 将会做为一个正常的响应返回。你必须主动检查响应的状态码并处理捕获的网络异常。


因此你必须在两个地方处理错误。但是,你可以使用 axios.js 解决这些问题,在添加额外代价的情况下使用更简洁的代码。使用 axios 的代码看起来就像这样:

fetchQuotes = () => {
this.setState({...this.state, isFetching: true})
axios.get(QUOTE_SERVICE_URL)
.then(response => this.setState({quotes: response.data,

isFetching: false}))
.catch(e => console.log(e);

}

这看起来差别并不大,但是这非常有帮助。使用 axios 添加新的记录代码也非常简洁。以下是 fetch 的版本:

handleSubmitWithFetch = event => {
let data = new FormData()
data.append('quote', this.state.quote)
fetch(this.props.quote_service_url,
{method: 'POST', body: data})
.then(response => response.json())
.catch(e => console.log(e));
event.preventDefault();

}

这是 axios 的版本:

handleSubmit = event => {
axios.post(this.props.quote_service_url,
{'quote': this.state.quote})
.then(r => console.log(r))
.catch(e => console.log(e));
event.preventDefault();
}
640?wx_fmt=png

在这篇教程中,你学到了如何在 React 组件中异步加载数据。我们也提到了相关的生命周期方法、轮询、进度条和错误的处理。


我们也了解到两个基于 promise 的库:fetch API 和 axios.js。现在,你可以构建自己的 React 应用了。


在最近几年中,React 越来越流行。事实上,市场有很多可以供购买、审查、部署的项目。 如果,你查找更多的 React 资源,不要迟疑请看这里

专注分享当下最实用的前端技术。关注前端达人,与达人一起学习进步!

长按关注"前端达人"

640?wx_fmt=gif 640?wx_fmt=jpeg

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值