前言

在日常的开发中,从服务器端异步获取数据并渲染是相当高频的操作。在以往使用React Class组件的时候,这种操作我们已经很熟悉了,即在Class组件的componentDidMount中通过ajax来获取数据并setState,触发组件更新。

随着Hook的到来,我们可以在一些场景中使用Hook的写法来替代Class的写法。但是Hook中没有setState、componentDidMount等函数,又如何做到从服务器端异步获取数据并渲染呢?本文将会介绍如何使用React的新特性Hook来编写组件并获取数据渲染。

数据渲染

先来看一个数据渲染的简单demo

import React, { useState } from 'react';
 
function App() {
 const [data, setData] = useState({ products: [{
 productId: '123',
 productName: 'macbook'
 }] });
 
 return (
 <ul>
 {data.products.map(i => (
 <li key={i.productId}>
  {i.productName}
 </li>
 ))}
 </ul>
 );
} 
export default App;

在demo中,通过useState创建了一个叫data的内部state,该state中有一个产品列表数据保存产品数据。App组件通过data中的products来渲染产品列表数据到页面中。

但现在是写死的一个数据,如果我们期望从服务器端获取数据并渲染,那么就需要在组件渲染完成时fetch服务端数据,然后通过setData去改变state触发渲染。我们接下来准备用axios来获取数据。

import React, { useState, useEffect } from 'react';
import axios from 'axios';
 
function App() {
 const [data, setData] = useState({ products: [{
 productId: '123',
 productName: 'macbook'
 }] });
 
 useEffect(async () => {
 const result = await axios(
 'https://c.com/api/products?date=today',
 );
 
 setData(result.data);
 });
 
 return (
 <ul>
 {data.products.map(i => (
 <li key={i.productId}>
  {i.productName}
 </li>
 ))}
 </ul>
 );
}
export default App;

代码中使用到的useEffect就是hook的其中一种,叫effect hook。useEffect会在每次组件渲染的时候触发,我们使用它来获取数据并更新state。但是上面的代码是有缺陷的,你发现了吗?

没错,只要你运行一下,你就会发现程序进入了一个死循环。因为useEffect不仅在组件didMounts的时候被触发了,还在didUpdate的时候被触发了。在useEffect中获取数据后,通过setDate改变state,触发组件渲染更新,从而又进入到了useEffect中,无限循环下去。这并不是我们想要的结果。我们最初想要的,只是希望在didMounts的时候获取一次数据而已。所以,这种情况下,我们必须要给useEffect方法的第二个参数传入一个空[],以使得useEffect中的逻辑只在组件didMounts的时候被执行。

import React, { useState, useEffect } from 'react';
import axios from 'axios';
 
function App() {
 const [data, setData] = useState({ products: [{
 productId: '123',
 productName: 'macbook'
 }] });
 
 useEffect(async () => {
 const result = await axios(
 'https://c.com/api/products?date=today',
 );
 
 setData(result.data);
 },[]); //重点
 
 return (
 <ul>
 {data.products.map(i => (
 <li key={i.productId}>
  {i.productName}
 </li>
 ))}
 </ul>
 );
}
export default App;

虽然看起来这个错误比较低级,但确实比较多人在新上手hook时常常犯的问题。

当然,useEffect第二个参数,也可以传入值。当如果有值的时候,那useEffect会在这些值更新的时候触发。如果只是个空数组,则只会在didMounts的时候触发。

另外,执行这段代码,你会看到控制台警告,Promises and useEffect(async () => ...) are not supported, but you can call an async function inside an effect.。所以如果要使用async,需要修改下写法。

import React, { useState, useEffect } from 'react';
import axios from 'axios';
 
function App() {
 const [data, setData] = useState({ products: [{
 productId: '123',
 productName: 'macbook'
 }] });
 
 useEffect(() => {
 const fetchData = async()=>{
 const result = await axios(
  'https://c.com/api/products?date=today',
 );
 setData(result.data);
 }
 fetchData();
 },[]); 
 
 return (
 <ul>
 {data.products.map(i => (
 <li key={i.productId}>
  {i.productName}
 </li>
 ))}
 </ul>
 );
}
export default App;

体验优化

一般的应用在某些请求过程的交互设计上,会加上loading来缓解用户焦虑。那在Hook的写法中,如何实现呢?下面将会介绍。

import React, { useState, useEffect } from 'react';
import axios from 'axios';
 
function App() {
 const [data, setData] = useState({ products: [{
 productId: '123',
 productName: 'macbook'
 }] });
 const [isLoading, setIsLoading] = useState(false);
 
 useEffect(() => {
 const fetchData = async()=>{
 setIsLoading(true);
 const result = await axios(
  'https://c.com/api/products?date=today',
 );
 setData(result.data);
 setIsLoading(false);
 }
 fetchData();
 },[]); 
 
 return (
 {isLoading ? (
 <div>Loading ...</div>
 ) : (
 <ul>
 {data.products.map(i => (
 <li key={i.productId}>
  {i.productName}
 </li>
 ))}
 </ul>
 )};
}
export default App;

这里通过加入一个叫isLoading的state来实现。我们在fetch的开始和结束去改变isLoading的值,来控制return返回的组件内容,从而在请求前显示Loading组件,在请求后显示产品列表。

错误处理

请求的过程经常会由于各种原因失败,比如网络、服务器错误等等。所以错误处理必不可少的。

import React, { useState, useEffect } from 'react';
import axios from 'axios';
 
function App() {
 const [data, setData] = useState({ products: [{
 productId: '123',
 productName: 'macbook'
 }] });
 const [isLoading, setIsLoading] = useState(false);
 const [isError, setIsError] = useState(false);
 
 useEffect(() => {
 const fetchData = async()=>{
 setIsError(false);
 setIsLoading(true);

 try{
  const result = await axios(
  'https://c.com/api/products?date=today',
  );
  setData(result.data);
 }catch(e){
  setIsError(true);
 }
 setIsLoading(false);
 }
 fetchData();
 },[]); 
 
 return (
 <div>
 {isError && <div>出错了...</div>}
 {isLoading ? (
 <div>Loading ...</div>
 ) : (
 <ul>
 {data.products.map(i => (
 <li key={i.productId}>
  {i.productName}
 </li>
 ))}
 </ul>
 )};
 </div>
 
}
 
export default App;

当请求出错时,isError会被设置为true,触发渲染时,错误提示组件就会被渲染出来。这里的处理比较简单,在真实场景中,你可以在错误处理时加入更复杂的逻辑。isError会在每次hook运行的时候被重置。

最后

读到这你已经基本学会了如何使用React Hooks获取数据并渲染组件了。

到此这篇关于如何使用React Hooks请求数据并渲染的文章就介绍到这了,更多相关React Hooks请求数据并渲染内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

详解如何使用React Hooks请求数据并渲染的更多相关文章

  1. ios – React native链接到另一个应用程序

    如果是错误的,有人知道如何调用正确的吗?

  2. ios – React Native – 在异步操作后导航

    我正在使用ReactNative和Redux开发移动应用程序,我正面临着软件设计问题.我想调用RESTAPI进行登录,如果该操作成功,则导航到主视图.我正在使用redux和thunk所以我已经实现了异步操作,所以我的主要疑问是:我应该把逻辑导航到主视图?我可以直接从动作访问导航器对象并在那里执行导航吗?.我对组件中的逻辑没有信心.似乎不是一个好习惯.有没有其他方法可以做到这一点?

  3. 在ios中使用带有React Native(0.43.4)的cocoapods的正确方法是什么?

    我已经挖掘了很多帖子试图使用cocoapods为本地ios库设置一个反应原生项目,但我不可避免地在#import中找到了丢失文件的错误.我的AppDelegate.m文件中的语句.什么是使用反应原生的可可豆荚的正确方法?在这篇文章发表时,我目前的RN版本是0.43.4,而我正在使用Xcode8.2.1.这是我的过程,好奇我可能会出错:1)

  4. ios – React Native WebView滚动行为无法按预期工作

    如何确保滚动事件的行为与ReactNative应用程序中的浏览器相同?

  5. ios – React Native – BVLinearGradient – 找不到’React/RCTViewManager.h’文件

    谢谢.解决方法几天前我遇到了完全相同的问题.问题是在构建应用程序时React尚未链接.试试这个:转到Product=>Scheme=>管理方案…=>点击你的应用程序Scheme,然后点击Edit=>转到Build选项卡=>取消选中ParallelizeBuild然后点击标志添加目标=>搜索React,选择第一个名为React的目标,然后单击Add然后在目标列表中选择React并将其向上拖动到该列表中的第一个.然后转到Product=>再次清理并构建项目.这应该有所帮助.

  6. ios – React Native – NSNumber无法转换为NSString

    解决方法在你的fontWeight()函数中也许变成:

  7. ios – React native error – react-native-xcode.sh:line 45:react-native:command not found命令/ bin/sh失败,退出代码127

    尝试构建任何(新的或旧的)项目时出现此错误.我的节点是版本4.2.1,react-native是版本0.1.7.我看过其他有相同问题的人,所以我已经更新了本机的最新版本,但是我仍然无法通过xcode构建任何项目.解决方法要解决此问题,请使用以下步骤:>使用节点版本v4.2.1>cd进入[你的应用]/node_modules/react-native/packager>$sh./packager.s

  8. 反应原生 – 如何通过Xcode构建React Native iOS应用程序到设备?

    我试图将AwesomeProject应用程序构建到设备上.构建成功并启动屏幕显示,但后来我看到一个红色的“无法连接到开发服务器”屏幕.它表示“确保节点服务器正在运行–从Reactroot运行”npmstart“.看起来节点服务器已经运行,因为当我做npm启动时,我收到一个EADDRINUSE消息,表示该端口已经在使用.解决方法从设备访问开发服务器您可以使用开发服务器快速迭代设备.要做到这一点,你的

  9. 静音iOS推送通知与React Native应用程序在后台

    我有一个ReactNative应用程序,我试图获得一个发送到JavaScript处理程序的静默iOS推送通知.我看到的行为是AppDelegate中的didReceiveRemoteNotification函数被调用,但是我的JavaScript中的处理程序不会被调用,除非应用程序在前台,或者最近才被关闭.我很困惑的事情显然是应用程序正在被唤醒,并且它的didReceiveRemoteNotifi

  10. 如何为iOS的React Native设置分析

    所以我已经完成了一个针对iOS的ReactNative项目,但是我想在其中分析.我尝试了react-native-google-analytics软件包,但是问题阻止了它的正常工作.此外,react-native-cordova-plugin软件包只适用于Android,因此插入Cordova插件进行分析的能力现在已成为问题.我也没有Swift/ObjectiveC的经验,所以将完全失去GA的插入.有没有人有任何建议如何连接GoogleAnalytics的ReactNativeforiOS?

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部