在 React 应用中获取数据

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

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

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

开始

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

> create-react-app react-data-fetcher

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

创建简单的服务

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

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

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

App 预览

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

这是截图:

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

显示 Quotes

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

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

通过 Fetch 获取远程数据

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

何时何地执行获取数据的代码

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

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

看起来就像这样:

componentDidMount() {
    this.fetchQuotes()
}

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

数据更新频率

在 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。

加载数据延迟的处理

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

在演示 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));
}

错误的处理

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

Fetch API vs. Axios

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

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

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

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

原文发布于微信公众号 - 前端达人(frontend84)

原文发表时间:2018-09-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏前端儿

iPhone页面的常用调试方法

某些页面需要设置HOST才能进行访问,在iPhone上不好设置HOST,所以需要一些代理工具帮助我们

4101
来自专栏云计算教程系列

如何使用WP-CLI安装WordPress

很多人都熟悉WordPress的安装,Wordpress安装起来非常简单,其号称5分钟快速安装。但是,当您需要部署多个Wordpress时,重复的工作会拖慢你大...

1632
来自专栏软件测试经验与教训

Fiddler用法整理

读书与实践是获取知识的主要渠道,学习的权力只掌握在每个人自己手中,让学习成为一种生活的习惯,这比任何名牌大学的校徽重要得多!

1561
来自专栏张戈的专栏

借助PageSpeed,为Nginx网站服务器提速

网站加载速度越快,访客互动性、留住率和转换率就越高,这早已不是什么秘密。网站每延迟 100 毫秒,亚马逊的销售额就会减少 1%;延迟增加 500 毫秒,这意味着...

3947
来自专栏青玉伏案

iOS逆向工程之Hopper+LLDB调试第三方App

LLDB是Low Level Debugger的简称,在iOS开发的调试中LLDB是经常使用的,LLDB是Xcode内置的动态调试工具。使用LLDB可以动态的调...

4019
来自专栏小尘哥的专栏

前后端分离Nuxt.js解决SEO问题

背景:由于后端程序猿通常对CSS 、JS掌握不是特别好,通常的开发模式,UI把静态html做好交给程序猿,程序猿开发,把静态html变成动态的时候经常会有各种样...

4234
来自专栏编程微刊

微信小程序云开发数据库操作查询记录

数据库操作参考API:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-cl...

4.3K3
来自专栏全栈之路

vue.js安装心得

npm是nodejs的包管理器,所以之前只想找npm,而不想下载nodejs,最后闹了笑话。

1582
来自专栏崔庆才的专栏

只会用Selenium爬网页?Appium爬App了解一下

3.2K5
来自专栏云计算教程系列

如何在Ubuntu 14.04上使用Fail2Ban保护WordPress

WordPress是一个非常强大的内容管理系统(CMS),是免费和开源的。因为任何人都可以发表评论,创建一个帐户,并在WordPress上发帖,许多恶意行为者已...

1550

扫码关注云+社区

领取腾讯云代金券