取消请求

React 中当前正在发出请求的组件从页面上卸载了,理想情况下这个请求也应该取消掉,那么如何把请求的取消和页面的卸载关联在一起呢?

这里要考虑利用 useEffect 传入函数的返回值:

useEffect(() => {
return () => {
// 页面卸载时执行
};
}, []);
复制代码

假设我们的请求是利用 fetch,那么还有一个需要运用的知识点:AbortController,简单看一下它的用法:

const abortController = new AbortController();

fetch(url, {
// 这里传入 signal 进行关联
signal: abortController.signal,
}); // 这里调用 abort 即可取消请求
abortController.abort();
复制代码

那么结合 React 封装一个 useFetch 的 hook:

export function useFetch = (config, deps) => {
const abortController = new AbortController()
const [loading, setLoading] = useState(false)
const [result, setResult] = useState() useEffect(() => {
setLoading(true)
fetch({
...config,
signal: abortController.signal
})
.then((res) => setResult(res))
.finally(() => setLoading(false))
}, deps) useEffect(() => {
return () => abortController.abort()
}, []) return { result, loading }
}
复制代码

那么比如在路由发生切换,Tab 发生切换等场景下,被卸载掉的组件发出的请求也会被中断。

深比较依赖

在使用 useEffect 等需要传入依赖的 hook 时,最理想的状况是所有依赖都在真正发生变化的时候才去改变自身的引用地址,但是有些依赖不太听话,每次渲染都会重新生成一个引用,但是内部的值却没变,这可能会让 useEffect 对于依赖的「浅比较」没法正常工作。

比如说:

const getDep = () => {
return {
foo: 'bar',
};
}; useEffect(() => {
// 无限循环了
}, [getDep()]);
复制代码

这是一个人为的例子,由于 getDeps 函数返回的对象每次执行都是一个全新的引用,所以会导致触发渲染->effect->渲染->effect 的无限更新。

有一个比较取巧的解决办法,把依赖转为字符串:

const getDep = () => {
return {
foo: 'bar',
};
}; const dep = JSON.stringify(getDeps()); useEffect(() => {
// ok!
}, [dep]);
复制代码

这样对比的就是字符串 "{ foo: 'bar' }" 的值,而不是对象的引用,那么只有在值真正发生变化时才会触发更新。

当然最好还是用社区提供的方案:useDeepCompareEffect,它选用深比较策略,对于对象依赖来说,它逐个对比 key 和 value,在性能上会有所牺牲。

如果你的某个依赖触发了多次无意义的接口请求,那么宁愿选用 useDeepCompareEffect ,在对象比较上多花费些时间可比重复请求接口要好得多。

useDeepCompareEffect 大致原理:

import { isEqual } from 'lodash';
export function useDeepCompareEffect(fn, deps) {
const trigger = useRef(0);
const prevDeps = useRef(deps);
if (!isEqual(prevDeps.current, deps)) {
trigger.current++;
}
prevDeps.current = deps;
return useEffect(fn, [trigger.current]);
}
复制代码

真正传入 useEffect 用以更新的是 trigger 这个数字值。用useRef 保留上一次传入的依赖,每次都利用 lodash 的 isEqual 对本次依赖和旧依赖进行深比较,如果发生变化,则让 trigger 的值增加。

当然我们也可以用 fast-deep-equal 这个库,根据官方的 benchmark 对比,它比 lodash 的效率高 7 倍左右。

以 URL 为数据仓库

在公司内部的后台管理项目中,无论你做的系统面向的人群是运营还是开发,都会涉及到分享,那么保留「页面状态」就非常重要了。比如我是运营 A,在使用一个内部数据平台,我一定是想向运营 B 分享某 App 的消费数据的第二页,并且筛选为某个用户的状态的网页,并且进行讨论。那么状态和 URL 同步就尤为重要了。

在传统的状态管理思路中,我们需要在代码里用reduxrecoil等库去做一系列的数据管理,但是如果把 URL 后面的那串 query 想象成数据仓库呢?是不是也可以,尝试配合react-router封装一下。

export function useQuery() {
const history = useHistory();
const { search, pathname } = useLocation();
// 保存query状态
const queryState = useRef(qs.parse(search));
// 设置query
const setQuery = handler => {
const nextQuery = handler(queryState.current);
queryState.current = nextQuery;
// replace会使组件重新渲染
history.replace({
pathname: pathname,
search: qs.stringify(nextQuery),
});
};
return [queryState.current, setQuery];
}
复制代码

在组件中,可以这样使用:

const [query, setQuery] = useQuery();

// 接口请求依赖 page 和 size
useEffect(() => {
api.getUsers();
}, [query.page, query, size]); // 分页改变 触发接口重新请求
const onPageChange = page => {
setQuery(prevQuery => ({
...prevQuery,
page,
}));
};
复制代码

这样,所有的页面状态更改都会自动同步到 URL,非常方便。

React实用技巧的更多相关文章

  1. Notepad++ 实用技巧

    Notepad++是一款开源的文本编辑器,功能强大.很适合用于编辑.注释代码.它支持绝大部分主流的编程语言. 本文主要列举了本人在实际使用中遇到的一些技巧. 快捷键 自定义快捷键 首先,需要知道的是: ...

  2. javascript实用技巧、javascript高级技巧

    字号+作者:H5之家 来源:H5之家 2016-10-31 11:00 我要评论( ) 三零网提供网络编程. JavaScript 的技术文章javascript实用技巧.javascript高级技巧 ...

  3. iOS开发实用技巧—Objective-C中的各种遍历(迭代)方式

    iOS开发实用技巧—Objective-C中的各种遍历(迭代)方式 说明: 1)该文简短介绍在iOS开发中遍历字典.数组和集合的几种常见方式. 2)该文对应的代码可以在下面的地址获得:https:// ...

  4. iOS开发实用技巧—在手机浏览器头部弹出app应用下载提示

    iOS开发实用技巧—在手机浏览器头部弹出app应用下载提示 本文介绍其简单使用: 第一步:在本地建立一个访问的服务端.  打开本地终端,在本地新建一个文件夹,在该文件夹中存放测试的html页面.   ...

  5. iOS开发实用技巧—项目新特性页面的处理

    iOS开发实用技巧篇—项目新特性页面的处理 说明:本文主要说明在项目开发中会涉及到的最最简单的新特性界面(实用UIScrollView展示多张图片的轮播)的处理. 代码示例: 新建一个专门的处理新特性 ...

  6. IOS 网络浅析-(十三 SDWebImage 实用技巧)

    IOS 网络浅析-(十三 SDWebImage 实用技巧) 首先让我描述一下为了什么而产生的实用技巧.(在TableView.CollectionView中)当用户所处环境WiFi网速不够快(不能立即 ...

  7. NSString的八条实用技巧

    NSString的八条实用技巧 有一篇文章写了:iOS开发之NSString的几条实用技巧 , 今天这篇,我们讲讲NSString的八条实用技巧.大家可以收藏起来,方便开发随时可以复制粘贴. 0.首字 ...

  8. ###《VIM实用技巧》

    ###<VIM实用技巧> #@author: gr #@date: 2015-11-20 #@email: forgerui@gmail.com <VIM实用技巧>阅读笔记. ...

  9. PowerDesigner实用技巧小结(3)

    PowerDesigner实用技巧小结(3) PowerDesigner 技巧小结 sqlserver数据库databasevbscriptsqldomain 1.PowerDesigner 使用 M ...

随机推荐

  1. Spring-cloud-netflix-hystrix

    服务注册中心eureka-server已经搭好,并且SPRING-CLOUD-NETFLIX-EUREKA-CLIENT-APPLICATION提供一个hello服务 畏怯还编写一个eureka-cl ...

  2. LVS之DR模式部署

    一.LVS-DR数据包流向分析 为方便进行原理分析,将Client与群集机器放在同一网络中,数据包流经的路线为1-2-3-41.Client 向目标 VIP 发出请求,Director(负载均衡器)接 ...

  3. VuePress 最新教程

    VuePress 最新教程 https://vuepress.vuejs.org/ https://github.com/vuejs/vuepress VuePress plugins 插件通常会为 ...

  4. Markdown & Static Site Generator

    Markdown & Static Site Generator https://www.gitbook.com/ https://vuepress.vuejs.org/ https://ww ...

  5. taro 渲染 html

    taro 渲染 html https://taro-docs.jd.com/taro/next/docs/next/html.html // Taro 更推荐使用框架自带的渲染 HTML 方式 // ...

  6. ng 基础

    文档 组件的工作只管用户体验,而不用顾及其它. 它应该提供用于数据绑定的属性和方法,以便作为视图和应用逻辑的中介者 组件应该把诸如从服务器获取数据.验证用户输入或直接往控制台中写日志等工作委托给各种服 ...

  7. VAST重磅出击,NGK网络搜索量超越ETH!

    Wechat指数中,NGK超越ETH,NGK搜索指数是157648点位,单日环比上涨11.95%,ETH搜索指数是115604点位,就连区块链标杆的BTC也仅仅只有171669点位,我们可清楚的看到N ...

  8. DBA 的效率加速器——CloudQuery v1.3.2 上线!

    嘿,兄弟,我们好久不见,你在哪里 嘿,朋友,如果真的是你,请打声招呼 我说好久不见,你去哪里 你却对我说,我去江湖 我去看 CloudQuery v1.3.2,看看新增了哪些好用的小功能! 一.自动/ ...

  9. 深入剖析 ConcurrentHashMap

    自建博客地址:https://bytelife.net,欢迎访问! 本文为博客自动同步文章,为了更好的阅读体验,建议您移步至我的博客 本文作者: Jeffrey 本文链接: https://bytel ...

  10. Spring Cloud基础

    1.网站架构演变过程 传统架构(单点应用SSM或SSH)→分布式架构(项目拆分)→SOA架构(面向服务架构)→微服务架构 2.微服务概述 2.1SOA架构 面向服务的架构(SOA)是一个组件模型,它将 ...