React中的生命周期方法,hooks, suspense获取数据的优缺点比较
在执行诸如数据提取之类的I / O操作时,您必须启动提取操作,等待响应,将响应数据保存到组件的状态,最后进行渲染。
异步数据获取需要付出额外的努力才能适应React的声明性。逐步改进React可以最大程度地减少这种额外的工作。
生命周期方法,hooks和suspense是在React中获取数据的方法。我将在示例和演示中对其进行描述,并比较出每个示例的优缺点。
了解每种方法的来龙去脉将使您更好地编码异步操作。
1.使用生命周期方法获取数据
应用程序Employees.org必须做两件事:
- 最初获取公司20名员工。
- 筛选名称包含查询的员工。

在实现这些要求之前,请回顾类组件的2个生命周期方法:
componentDidMount()
:挂载只后执行一次componentDidUpdate(prevProps)
:在props或state改变时执行
<EmployeesPage>
使用以下两种生命周期方法实现提取逻辑:
import EmployeesList from "./EmployeesList";
import { fetchEmployees } from "./fake-fetch";
class EmployeesPage extends Component {
constructor(props) {
super(props);
this.state = { employees: [], isFetching: true };
}
componentDidMount() {
this.fetch();
}
componentDidUpdate(prevProps) {
if (prevProps.query !== this.props.query) {
this.fetch();
}
}
async fetch() {
this.setState({ isFetching: true });
const employees = await fetchEmployees(this.props.query);
this.setState({ employees, isFetching: false });
}
render() {
const { isFetching, employees } = this.state;
if (isFetching) {
return <div>Fetching employees....</div>;
}
return <EmployeesList employees={employees} />;
}
}
<EmployeesPage>
有一个fetch()
处理获取的异步方法。提取请求完成后,组件状态将更新为fetched employees
。
this.fetch()
在componentDidMount()
生命周期方法中执行:最初呈现组件时,这开始获取员工。
当用户在输入字段中输入查询时,props 上query
会更新。每次发生时,this.fetch()
均由componentDidUpdate()
执行,以实现对员工的过滤。
尽管生命周期方法相对容易掌握,但是基于类的方法却遇到了样板代码和可重用性的难题。
好处
直观
易懂:生命周期方法会componentDidMount()
在首次渲染componentDidUpdate()
时启动获取,并在props更改时重新获取数据。
缺点
基于类的组件需要“仪式”代码:继承React.Component
,super(props)
在内部调用constructor()
等。
this
使用this
关键字很麻烦。
重复代码
里面的代码componentDidMount()
和componentDidUpdate()
大部分重复。
难以复用
员工获取逻辑很难在另一个组件中复用。
2.使用hooks获取数据
hooks是基于类的获取的更好的替代方法。作为简单的函数,hooks没有“仪式”代码,并且更易于重用。
让我们回想一下useEffect(callback[, deps])函数
。该回调callback函数
在挂载后以及deps
更改后渲染执行。
在以下示例中<EmployeesPage>
用于useEffect()
获取员工数据:
<EmployeesPage>
使用hooks简化了很多。
内部<EmployeesPage>
功能组件在初始渲染后,useEffect(fetch, [query])
执行fetch
回调。此外,fetch
在稍后渲染之后会被调用,仅当props属性上的query
更改时才被调用。
hooks允许你从组件中提取员工获取逻辑<EmployeesPage>
。让我们这样做:
import React, { useState } from 'react';
import EmployeesList from "./EmployeesList";
import { fetchEmployees } from "./fake-fetch";
function useEmployeesFetch(query) {
const [isFetching, setFetching] = useState(false);
const [employees, setEmployees] = useState([]);
useEffect(function fetch {
(async function() {
setFetching(true);
setEmployees(await fetchEmployees(query));
setFetching(false);
})();
}, [query]);
return [isFetching, employees];
}
function EmployeesPage({ query }) {
const [employees, isFetching] = useEmployeesFetch(query);
if (isFetching) {
return <div>Fetching employees....</div>;
}
return <EmployeesList employees={employees} />;
}
该组件<EmployeesPage>
不会因获取逻辑而杂乱无章,而是直接完成了工作:渲染UI元素。
更好的是,您可以useEmployeesFetch()
在需要获取员工的任何其他组件中重用。
好处
hooks简单钩子没有样板代码,因为它们是普通函数。
可重用性
在hooks中实现的获取逻辑易于重用。
缺点
hooks在一定程度上是违反直觉的,因此在使用之前必须先了解它们。hooks依赖于封闭,因此请一定也非常了解它们。
对于钩子,您仍然必须使用命令式方法来执行数据提取。
3.使用suspense获取数据
Suspense提供了一种声明式方法来在React中异步获取数据。
注意:截至2019年11月,暂停处于试验阶段。
<Suspense>
包装执行异步操作的组件:
<Suspense fallback={<span>Fetch in progress...</span>}>
<FetchSomething />
</Suspense>
进行抓取时,suspense将呈现fallback
内容。稍后,当获取完成时,将<FetchSomething />
使用获取的数据进行暂挂渲染。
让我们看看员工的申请是如何悬而未决的:
import React, { Suspense } from "react";
import EmployeesList from "./EmployeesList";
function EmployeesPage({ resource }) {
return (
<Suspense fallback={<h1>Fetching employees....</h1>}> <EmployeesFetch resource={resource} /> </Suspense> );
}
function EmployeesFetch({ resource }) {
const employees = resource.employees.read();
return <EmployeesList employees={employees} />;
}
<EmployeesPage>
使用suspense处理内部提取组件<EmployeesFetch>
。
resource.employees
内部<EmployeesFetch>
是一个特别包装的承诺,在后台与suspense进行了交流。通过这种方式,Suspense可以知道“”渲染的“挂起”时间<EmployeesFetch>
,以及资源准备就绪后的时间。
这是一个巨大的胜利:Suspense以声明性和同步方式处理异步操作。
这些组件不会杂乱如何获取数据的详细信息。而是它们以声明方式使用资源来呈现内容。async/await
组件内部没有生命周期,没有hooks,也没有回调:仅呈现资源。
好处
声明式
挂起允许您在React中声明式执行异步操作。
简单性
声明性代码易于使用。这些组件不会杂乱如何获取数据的详细信息。
与获取实现
的松耦合使用suspense的组件不知道如何获取数据:使用REST或GraphQL。暂挂设置了一个边界,该边界可保护获取的详细信息泄漏到您的组件中。
无竞争条件
如果启动了多个提取操作,则暂挂将使用最新的提取请求。
缺点
需要挂起需要专门的提取库或实现挂起获取接口的适配器。
4.关键要点
长期以来,生命周期方法一直是获取数据的唯一解决方案。但是,使用它们进行获取存在许多样板代码,重复和可重用性困难的问题。
使用hooks获取是更好的选择:减少样板代码。
Suspense的好处是声明式获取。您的组件不会因获取实现细节而混乱。Suspense更接近于React本身的声明性。