详解如何使用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 removeChild 使用注意事项
Apr 11 Javascript
javascript 循环读取JSON数据的代码
Jul 17 Javascript
推荐20家国外的脚本下载网站
Apr 28 Javascript
用JavaScript计算在UTF-8下存储字符串占用字节数
Aug 08 Javascript
IE6下javasc#ipt:void(0) 无效的解决方法
Dec 23 Javascript
node.js集成百度UE编辑器
Feb 05 Javascript
JavaScript函数节流和函数防抖之间的区别
Feb 15 Javascript
JavaScript深拷贝和浅拷贝概念与用法实例分析
Jun 07 Javascript
Vue-CLI 项目在pycharm中配置方法
Aug 30 Javascript
深入探索VueJS Scoped CSS 实现原理
Sep 23 Javascript
jquery 时间戳转日期过程详解
Oct 12 jQuery
Promise静态四兄弟实现示例详解
Jul 07 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 在5.1.* 和5.2.*之间 PDO数据库操作中的不同之处小结
2012/03/07 PHP
PHP中鲜为人知的10个函数
2014/02/28 PHP
PHP实现的汉字拼音转换和公历农历转换类及使用示例
2014/07/01 PHP
thinkphp3.x自定义Action、Model及View的简单实现方法
2016/05/19 PHP
Laravel+jQuery实现AJAX分页效果
2016/09/14 PHP
PHP实现简单ajax Loading加载功能示例
2016/12/28 PHP
js中的时间转换—毫秒转换成日期时间的示例代码
2014/01/26 Javascript
浅谈JavaScript中null和undefined
2015/07/09 Javascript
TypeScript Type Innference(类型判断)
2016/03/10 Javascript
js/jq仿window文件夹移动/剪切/复制等操作代码
2017/03/08 Javascript
javascript 中的try catch应用总结
2017/04/01 Javascript
Bootstrap弹出框之自定义悬停框标题、内容和样式示例代码
2017/07/11 Javascript
vue.js框架实现表单排序和分页效果
2017/08/09 Javascript
js获取css的各种样式并且设置他们的方法
2017/08/22 Javascript
利用Vue2.x开发实现JSON树的方法
2018/01/04 Javascript
基于react后端渲染模板引擎noox发布使用
2018/01/11 Javascript
基于vue.js中事件修饰符.self的用法(详解)
2018/02/23 Javascript
使用ECharts实现状态区间图
2018/10/25 Javascript
移动端(微信等使用vConsole调试console的方法
2019/03/05 Javascript
解决vue中el-tab-pane切换的问题
2020/07/19 Javascript
[43:24]完美世界DOTA2联赛PWL S3 INK ICE vs DLG 第二场 12.12
2020/12/17 DOTA
Python学习笔记之常用函数及说明
2014/05/23 Python
如何用Python做一个微信机器人自动拉群
2019/07/03 Python
python3实现从kafka获取数据,并解析为json格式,写入到mysql中
2019/12/23 Python
如何完美的建立一个python项目
2020/10/09 Python
python 牛顿法实现逻辑回归(Logistic Regression)
2020/10/15 Python
Python如何利用Har文件进行遍历指定字典替换提交的数据详解
2020/11/05 Python
html5 postMessage前端跨域并前端监听的方法示例
2018/11/01 HTML / CSS
Microsoft新加坡官方网站:购买微软最新软件和技术产品
2016/10/28 全球购物
Waterford加拿大官方网站:世界著名的水晶杯品牌
2016/11/01 全球购物
计算机大学生职业生涯规划书范文
2014/02/19 职场文书
专项法律服务方案
2014/06/11 职场文书
我的大学四年规划书范文2014
2014/09/26 职场文书
万能检讨书开头与结尾怎么写
2015/02/17 职场文书
停电通知范文
2015/04/16 职场文书
少先队入队仪式主持词
2015/07/04 职场文书