React Use Hook 尝鲜
Posted GoldenaArcher
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React Use Hook 尝鲜相关的知识,希望对你有一定的参考价值。
React Use Hook 尝鲜
最近继续在找处理 React 异步调用的方式……主要是现在需求比较复杂,用 cache query 的方式去实现有那么一丢丢的麻烦,又不是很想用额外的包,所以就想看看有没有比较好的一些处理方式。
当然,可以用到生产环境上的没找到,不过找到了一个还在试验阶段的新功能——use
hook,毫不夸张地说,这个 hook 打破了 React 既有的 hook 规范。
React 团队终于想不出什么正常点的名字,所以直接用 use
了吗
⚠️:还在试验阶段,未来不确定会不会被删除,友情提示不要用到生产环境
具体的 proposal 和 discussion 在这里: RFC: First class support for promises and async/await,里面还有一些挺有趣的 hooks 和用法,比如说已经被 merged 的 useSuspenseQuery
, 现在不工作的 export default async function ServerComponent()
等,总之这个 thread 感觉还是可以看看的。
基础用法
使用这个功能之前需要将 react 的版本设置为 experimental:
"dependencies":
"react": "experimental",
"react-dom": "experimental"
下面是一个基础的使用案例,目前在不借助第三方库的实现方式,异步的操作大概是借助 useEffect
和 useState
这样实现的:
import './App.css';
import useEffect, useState from 'react';
function App()
const [product, setProduct] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() =>
setLoading(true);
fetch('https://dummyjson.com/products/1')
.then((res) => res.json())
.then((json) => setProduct(json))
.catch((e) => console.error(e))
.finally(() => setLoading(false));
, []);
return (
<div className="App">
loading && <h1>Is Loading</h1>
!loading && JSON.stringify(product)
</div>
);
export default App;
在使用了 use
之后,可以简化成这样:
import './App.css';
import use from 'react';
const fetchProduct = fetch('https://dummyjson.com/products/1').then((res) =>
res.json()
);
function App()
const product = use(fetchProduct);
console.log(product);
return <div className="App">JSON.stringify(product)</div>;
export default App;
我试着尝试了一下 log 了一下 product,然后发现,product 不存在先被设置为 undefined
,随后在 API 调用成功后再被赋值的情况:
也就是说,使用 use
hook 并不遵从 React 目前其他的 hook 的生命周期方式,即先渲染组件,再处理完异步操作后渲染页面的步骤,而是直接等待异步操作完成后,再渲染页面。
这也就是当我修改了一下 API,让异步调用失败的时候,页面直接就白屏的因素:
render 部分完全没有调用,API 一旦失败了,那么这个页面就挂了。
目前关于怎样正式处理 loading 和 error 还没有一个定论,只是其中一个成员是这么说的:
总结一下就是,当 use
hook 处在一个薛定谔的状态时,会调用最近的 Suspense
,当 use
hook 调用失败时则会调用最近的 error boundary。
进阶之 Loading 与错误处理 的实现
使用 Suspense
和 error boundary 的部分,这里假设你知道 Suspense
和 error boundary,并知道怎么简单的实现这两个功能。
react 什么时候考虑吧 error boundary 的 hook 提上日程啊
loading 的处理
也就是利用 Suspense
的特性去实现,另外使用 Suspense
的好处在于,它会等到所有的 use
hooks 都完成了之后,再渲染页面。
也就是说,并不需要使用 Promise.all()
,只需要在 Suspense
中调用多个使用 use
的组件即可。
import './App.css';
import React, use, Suspense from 'react';
const fetchProduct = fetch('https://dummyjson.com/products/1').then((res) =>
res.json()
);
const Data = () =>
const product = use(fetchProduct);
return <div>JSON.stringify(product)</div>;
;
export default Data;
function App()
return (
<Suspense fallback=<div>loading</div>>
<Data />
</Suspense>
);
export default App;
效果如下:
这样的实现也有好有坏吧,官方说目前的操作是调用最近的 Suspense
,这个也的确会让 灵活处理 loading 状态 这一需求变得有些麻烦。
比如说有些情况下只是需要将 loading
传入一些表单中,让 UI 库去模拟拉取的状态,如 <Form loading=loading>
, <Table loading=loading>
这种情况。去梳理 DOM 树,并且在最近的结点处理或事创立 Suspense
可能会有些麻烦。
使用 error boundary
error boundary 甚至是一个 class based component 才有的功能:
class ErrorBoundry extends Component
state = hasError: false, error: null ;
static getDerivedStateFromError(error)
return
hasError: true,
error,
;
render()
if (this.state.hasError)
return this.props.fallback;
return this.props.children;
const Data = () =>
const product = use(fetchProduct);
return <div>JSON.stringify(product)</div>;
;
export default Data;
function App()
return (
<ErrorBoundry fallback=<div>Error</div>>
<Suspense fallback=<div>loading</div>>
<Data />
</Suspense>
</ErrorBoundry>
);
export default App;
同理,去梳理 DOM 树,并且在最近的结点处理或事创立 error boundary 也可能会有些麻烦。
另一个不遵从常规的特性
React 官方文档中单独分出一个节点说在顶部使用 hooks:Only Call Hooks at the Top Level,原文如下:
Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders.
但是 use
hook 打破了这条规范,如下面就是将 use
hook 放在了 if
中:
import React, use from 'react';
const fetchProduct = fetch('https://dummyjson.com/pdd/1').then((res) =>
res.json()
);
const Data = () =>
const bool = false;
if (bool)
const product = use(fetchProduct);
return <div>JSON.stringify(product)</div>;
return 'not fatched';
;
export default Data;
这其实也是另外一个我不太确定 use
hook 到底什么时候会被并入到生产阶段的原因,就是这个 hook 确实会完全打破 React 之前固有的 hook 规范。
当然,对于开发来说,这也更加的灵活,使用起来更方便就是了。
以上是关于React Use Hook 尝鲜的主要内容,如果未能解决你的问题,请参考以下文章
React JS 多个提交按钮 react-hook-form
文本字段更改的值未在 OnSubmit 中更新 - React-Hook-Form 和 React Js
react-hook-form 的 DefaultValues 未将值设置为 React JS 中的输入字段
React.js useState hook 导致过多的重新渲染并且无法更新我的状态