详解如何使用React Hooks请求数据并渲染


Posted in Javascript onOctober 18, 2020

前言

在日常的开发中,从服务器端异步获取数据并渲染是相当高频的操作。在以往使用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请求数据并渲染内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
基于jquery库的tab新形式使用
Nov 16 Javascript
jQuery性能优化的38个建议
Mar 04 Javascript
JQuery CheckBox(复选框)操作方法汇总
Apr 15 Javascript
jquery UI Datepicker时间控件的使用方法(终结版)
Nov 07 Javascript
移动端H5开发 Turn.js实现很棒的翻书效果
Jun 20 Javascript
学习Bootstrap滚动监听 附调用方法
Jul 02 Javascript
html+js+highcharts绘制圆饼图表的简单实例
Aug 04 Javascript
jQuery  ready方法实现原理详解
Oct 19 Javascript
JS实现数组按升序及降序排列的方法
Apr 26 Javascript
EasyUI的TreeGrid的过滤功能的解决思路
Aug 08 Javascript
Vue实现todolist删除功能
Jun 26 Javascript
微信小程序实现slideUp、slideDown滑动效果及点击空白隐藏功能示例
Dec 11 Javascript
js中复选框的取值及赋值示例详解
Oct 18 #Javascript
如何搭建一个完整的Vue3.0+ts的项目步骤
Oct 18 #Javascript
详解如何在Javascript中使用Object.freeze()
Oct 18 #Javascript
从表单校验看JavaScript策略模式的使用详解
Oct 17 #Javascript
关于IDEA中的.VUE文件报错 Export declarations are not supported by current JavaScript version
Oct 17 #Javascript
JS页面动态绘图工具SVG,Canvas,VML介简介
Oct 16 #Javascript
DWR内存兼容及无法调用问题解决方案
Oct 16 #Javascript
You might like
PHP怎样调用MSSQL的存储过程
2006/10/09 PHP
随时给自己贴的图片加文字的php代码
2007/03/08 PHP
PHPMyadmin 配置文件详解(配置)
2009/12/03 PHP
SESSION信息保存在哪个文件目录下以及能够用来保存什么类型的数据
2012/06/17 PHP
ThinkPHP行为扩展Behavior应用实例详解
2014/07/22 PHP
php ci 获取表单中多个同名input元素值的代码
2016/03/25 PHP
phpMyAdmin无法登陆的解决方法
2017/04/27 PHP
Laravel框架使用Seeder实现自动填充数据功能
2018/06/13 PHP
解决PHP使用CURL发送GET请求时传递参数的问题
2019/10/11 PHP
有趣的JavaScript数组长度问题代码说明
2011/01/20 Javascript
jquery插件tooltipv顶部淡入淡出效果使用示例
2013/12/05 Javascript
为开发者准备的10款最好的jQuery日历插件
2014/02/04 Javascript
JQuery中serialize() 序列化
2015/03/13 Javascript
jQuery Real Person验证码插件防止表单自动提交
2015/11/06 Javascript
jQuery配合coin-slider插件制作幻灯片效果的流程解析
2016/05/13 Javascript
三种方式实现瀑布流布局
2017/02/10 Javascript
微信小程序选择图片和放大预览图片功能
2017/11/02 Javascript
基于substring()和substr()的使用以及区别(实例讲解)
2017/12/28 Javascript
jQuery实现弹出层效果
2019/12/10 jQuery
js 计算月/周的第一天和最后一天代码
2020/02/01 Javascript
vue实现循环滚动列表
2020/06/30 Javascript
Javascript基于OOP实实现探测器功能代码实例
2020/08/26 Javascript
利用Python爬取可用的代理IP
2016/08/18 Python
python实现感知器
2017/12/19 Python
python 中字典嵌套列表的方法
2018/07/03 Python
Python变量、数据类型、数据类型转换相关函数用法实例详解
2020/01/09 Python
python3 中时间戳、时间、日期的转换和加减操作
2020/07/14 Python
使用纯HTML5编写一款网页上的时钟的代码分享
2015/11/16 HTML / CSS
飞利信loadrunner和软件测试笔试题
2012/09/22 面试题
介绍一下Java中的static关键字
2012/05/12 面试题
群众路线自查报告及整改措施
2014/11/04 职场文书
学生评语集锦
2015/01/04 职场文书
交通事故起诉书
2015/05/19 职场文书
2019求职信大礼包
2019/05/15 职场文书
在K8s上部署Redis集群的方法步骤
2021/04/27 Redis
Python快速优雅的批量修改Word文档样式
2021/05/20 Python