详解如何使用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 窗口加载蒙板 内嵌网页内容
Nov 19 Javascript
将两个div左右并列显示并实现点击标题切换内容
Oct 22 Javascript
jQuery操作Select的Option上下移动及移除添加等等
Nov 18 Javascript
JS 使用for循环遍历子节点查找元素
Sep 06 Javascript
pace.js页面加载进度条插件
Sep 29 Javascript
JS实现根据文件字节数返回文件大小的方法
Aug 02 Javascript
js实现背景图自适应窗口大小
Jan 10 Javascript
微信小程序中的onLoad详解及简单实例
Apr 05 Javascript
基于easyui checkbox 的一些操作处理方法
Jul 10 Javascript
jQuery插件DataTables分页开发心得体会
Aug 22 jQuery
监听angularJs列表数据是否渲染完毕的方法示例
Nov 07 Javascript
js实现图片区域可点击大小随意改变(适用移动端)代码实例
Sep 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
BBS(php &amp; mysql)完整版(五)
2006/10/09 PHP
php Xdebug 调试扩展的安装与使用.
2010/03/13 PHP
php实现根据url自动生成缩略图的方法
2014/09/23 PHP
Thinkphp和onethink实现微信支付插件
2016/04/13 PHP
php 广告点击统计代码(php+mysql)
2018/02/21 PHP
jquery中animate的stop()方法作用实例分析
2015/01/30 Javascript
jQuery插件bgStretcher.js实现全屏背景特效
2015/06/05 Javascript
javascript常用的方法分享
2015/07/01 Javascript
JavaScript实现上下浮动的窗口效果代码
2015/10/12 Javascript
javascript特殊日历控件分享
2016/03/07 Javascript
JavaScript:Array类型全面解析
2016/05/19 Javascript
Backbone中View之间传值的学习心得
2016/08/09 Javascript
利用CSS、JavaScript及Ajax实现图片预加载的方法
2016/11/29 Javascript
bootstrap中selectpicker下拉框使用方法实例
2018/03/22 Javascript
详解vue添加删除元素的方法
2018/06/30 Javascript
javascript中一些奇葩的日期换算方法总结
2018/11/14 Javascript
Vue-resource安装过程及使用方法解析
2020/07/21 Javascript
python翻译软件实现代码(使用google api完成)
2013/11/26 Python
详解Python3.6安装psutil模块和功能简介
2018/05/30 Python
Python中if elif else及缩进的使用简述
2018/05/31 Python
python 2.7.13 安装配置方法图文教程
2018/09/18 Python
python3实现字符串操作的实例代码
2019/04/16 Python
Django REST Framework 分页(Pagination)详解
2020/11/30 Python
python实现双人五子棋(终端版)
2020/12/30 Python
Python jieba库分词模式实例用法
2021/01/13 Python
CSS实现的一闪而过的图片闪光效果
2014/04/23 HTML / CSS
高级方案规划工程师岗位职责
2013/11/29 职场文书
营销总经理岗位职责
2014/02/02 职场文书
网络工程师专家职业发展路线
2014/02/14 职场文书
宿舍违规用电检讨书
2014/02/16 职场文书
电视购物广告词
2014/03/19 职场文书
入党积极分子学习党的纲领思想汇报
2014/09/13 职场文书
开发房地产协议书
2014/09/14 职场文书
2016暑期社会实践心得体会范文
2016/01/14 职场文书
大学毕业生自我鉴定范文
2019/06/21 职场文书
Python使用pandas导入csv文件内容的示例代码
2022/12/24 Python