专栏首页前端达人在 React 应用中获取数据

在 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),作者:Gigi Sayfan

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

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

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JavaScript 数据结构:栈和队列

    上周小编已经介绍了什么是数据结构,没看过的同学,可以点击《JavaScript 数据结构:什么是数据结构》,今天小编会和大家一起学习栈和队列。

    前端达人
  • 【数据结构基础】队列简介(使用ES6)

    上一篇系列文章《【数据结构基础】栈简介(使用ES6)》笔者介绍了什么是数据结构和什么是栈及相关代码实现,本篇文章笔者给大家介绍下什么是队列以及相关的代码实现。

    前端达人
  • 【数据结构基础】队列简介(使用ES6)

    在上一篇系列文章《【数据结构基础】栈简介(使用ES6)》笔者介绍了什么是数据结构、什么是栈及相关代码实现,本篇文章笔者给大家介绍下什么是队列以及相关的代码实现。

    前端达人
  • React Native之React速学教程(下)

    React Native之React速学教程(下) 本文出自《React Native学习笔记》系列文章。 React Native是基于React的,在开发R...

    CrazyCodeBoy
  • Promise的简单实现

    这个fetch()的方法返回了一个Promise对象,接着我们就可以用then来对获得的数据进行处理,catch来捕获可能的错误。

    IMWeb前端团队
  • 归纳总结this的指向问题

    7.函数调用时如果绑定了bind,那么函数中的this指向了bind中绑定的元素

    FinGet
  • vue封装一个简单的div框选时间的组件

    技术需要积累,有时间我把我之前写的还不错的组件都开源出来。并尝试vue和react 两种方式的组件封装。今天简单写下鼠标框选div选中效果的封装吧。

    Java帮帮
  • Promise的简单实现

    本篇文章通过构建一个简单的Promise对象来了解如何做到异步获得数据。 使用方法 const fetch = function(url) { return...

    IMWeb前端团队
  • Change Detection And Batch Update

    在传统的WEB开发中,当与用户或服务器发生交互时,需要我们手动获取数据并更新DOM,这个过程是繁琐的、易错的。 特别是当页面功能过于复杂时,我们既要关注数据的变...

    IMWeb前端团队
  • 你不知道的 this 指向优先级

    本文会以详细讲解一道 字节面试题 的方式,循序渐进完全搞定 js 中 this 指向优先级的问题。 ⛹‍♂⛹‍♂ js 中的 this 指向问题应该是一个讨论了...

    一只图雀

扫码关注云+社区

领取腾讯云代金券