详解如何使用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 相关文章推荐
JavaScript DOM 添加事件
Feb 14 Javascript
jquery checkbox全选、取消全选实现代码
Mar 05 Javascript
使用JS进行目录上传(相当于批量上传)
Dec 05 Javascript
js模拟select下拉菜单控件的代码
May 08 Javascript
解析Javascript小括号“()”的多义性
Dec 03 Javascript
XML、HTML、CSS与JS的区别整理
Feb 18 Javascript
前端弹出对话框 js实现ajax交互
Sep 09 Javascript
ionic中列表项增加和删除的实现方法
Jan 22 Javascript
Angular使用$http.jsonp发送跨站请求的方法
Mar 16 Javascript
微信小程序实现上传word、txt、Excel、PPT等文件功能
May 23 Javascript
vue如何搭建多页面多系统应用
Jun 17 Javascript
Vue和React有哪些区别
Sep 12 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设计模式 php实现观察者模式(Observer)
2015/12/09 PHP
php curl中gzip的压缩性能测试实例分析
2016/11/08 PHP
详解PHP中mb_strpos的使用
2018/02/04 PHP
新浪刚打开页面出来的全屏广告代码
2007/04/02 Javascript
动态的9*9乘法表效果的实现代码
2016/05/16 Javascript
JS面试题---关于算法台阶的问题
2016/07/26 Javascript
JS实现动态增加和删除li标签行的实例代码
2016/10/16 Javascript
Angularjs中的页面访问权限怎么设置
2016/11/11 Javascript
JavaScript数组操作详解
2017/02/04 Javascript
详解Angularjs 如何自定义Img的ng-load 事件
2017/02/15 Javascript
canvas红包照片实例分享
2017/02/28 Javascript
nodejs和C语言插入mysql数据库乱码问题的解决方法
2017/04/14 NodeJs
JavaScript实现移动端页面按手机屏幕分辨率自动缩放的最强代码
2017/08/18 Javascript
React复制到剪贴板的示例代码
2017/08/22 Javascript
JS中DOM元素的attribute与property属性示例详解
2018/09/04 Javascript
Bootstrap-table自定义可编辑每页显示记录数
2018/09/07 Javascript
vue实现的双向数据绑定操作示例
2018/12/04 Javascript
详解vue在项目中使用百度地图
2019/03/26 Javascript
详解vue-cli+element-ui树形表格(多级表格折腾小计)
2019/04/17 Javascript
VUE 实现复制内容到剪贴板的两种方法
2019/04/24 Javascript
使用vuex较为优雅的实现一个购物车功能的示例代码
2019/12/09 Javascript
pygame学习笔记(4):声音控制
2015/04/15 Python
Python实现朴素贝叶斯分类器的方法详解
2018/07/04 Python
python使用配置文件过程详解
2019/12/28 Python
python主要用于哪些方向
2020/07/05 Python
CSS3实现div从下往上滑入滑出效果示例
2020/04/28 HTML / CSS
联想印度官方网上商店:Lenovo India
2019/08/24 全球购物
什么是数组名
2012/05/10 面试题
个人简历中的自我评价范例
2013/10/29 职场文书
中学生自我评价范文
2014/02/08 职场文书
安全生产演讲稿
2014/05/09 职场文书
十佳党员事迹材料
2014/08/28 职场文书
先进班组材料范文
2014/12/25 职场文书
关爱留守儿童主题班会
2015/08/13 职场文书
python 制作一个gui界面的翻译工具
2021/05/14 Python
springboot 全局异常处理和统一响应对象的处理方式
2022/06/28 Java/Android