React实用技巧
取消请求
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 同步就尤为重要了。
在传统的状态管理思路中,我们需要在代码里用redux
、recoil
等库去做一系列的数据管理,但是如果把 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实用技巧的更多相关文章
- Notepad++ 实用技巧
Notepad++是一款开源的文本编辑器,功能强大.很适合用于编辑.注释代码.它支持绝大部分主流的编程语言. 本文主要列举了本人在实际使用中遇到的一些技巧. 快捷键 自定义快捷键 首先,需要知道的是: ...
- javascript实用技巧、javascript高级技巧
字号+作者:H5之家 来源:H5之家 2016-10-31 11:00 我要评论( ) 三零网提供网络编程. JavaScript 的技术文章javascript实用技巧.javascript高级技巧 ...
- iOS开发实用技巧—Objective-C中的各种遍历(迭代)方式
iOS开发实用技巧—Objective-C中的各种遍历(迭代)方式 说明: 1)该文简短介绍在iOS开发中遍历字典.数组和集合的几种常见方式. 2)该文对应的代码可以在下面的地址获得:https:// ...
- iOS开发实用技巧—在手机浏览器头部弹出app应用下载提示
iOS开发实用技巧—在手机浏览器头部弹出app应用下载提示 本文介绍其简单使用: 第一步:在本地建立一个访问的服务端. 打开本地终端,在本地新建一个文件夹,在该文件夹中存放测试的html页面. ...
- iOS开发实用技巧—项目新特性页面的处理
iOS开发实用技巧篇—项目新特性页面的处理 说明:本文主要说明在项目开发中会涉及到的最最简单的新特性界面(实用UIScrollView展示多张图片的轮播)的处理. 代码示例: 新建一个专门的处理新特性 ...
- IOS 网络浅析-(十三 SDWebImage 实用技巧)
IOS 网络浅析-(十三 SDWebImage 实用技巧) 首先让我描述一下为了什么而产生的实用技巧.(在TableView.CollectionView中)当用户所处环境WiFi网速不够快(不能立即 ...
- NSString的八条实用技巧
NSString的八条实用技巧 有一篇文章写了:iOS开发之NSString的几条实用技巧 , 今天这篇,我们讲讲NSString的八条实用技巧.大家可以收藏起来,方便开发随时可以复制粘贴. 0.首字 ...
- ###《VIM实用技巧》
###<VIM实用技巧> #@author: gr #@date: 2015-11-20 #@email: forgerui@gmail.com <VIM实用技巧>阅读笔记. ...
- PowerDesigner实用技巧小结(3)
PowerDesigner实用技巧小结(3) PowerDesigner 技巧小结 sqlserver数据库databasevbscriptsqldomain 1.PowerDesigner 使用 M ...
随机推荐
- wordpress 主题安装 您点击的链接已过期 nginx 出现413 Request Entity Too Large
1 nginx 出现413 Request Entity Too Large 问题是限制上传大小,解决: 1.打开nginx配置文件 nginx.conf, 路径一般是:/etc/nginx/ngin ...
- CodeForces - 13E(分块)
Little Petya likes to play a lot. Most of all he likes to play a game «Holes». This is a game for on ...
- 域渗透——获得域控服务器的NTDS.dit文件
0x00 前言 在之前的文章<导出当前域内所有用户hash的技术整理>曾介绍过通过Volume Shadow Copy实现对ntds.dit文件的复制, 可用来导出域内所有用户hash.本 ...
- Ubuntu-16.04下Docker通过阿里云镜像安装(apt-get)
由于通过官方路径安装docker时总是连接不上,所以从网上找了半天,通过阿里云镜像安装docker,我的Linux是ubuntu-16.04 一.配置源里的阿里云镜像仓库 sudo vim /etc/ ...
- 【GitChat首秀:限时免费】互联网测试岗校招的那些事儿
2020 校园秋招即将结束,2021 校招春招即将开始. 作为一名扎根互联网近十年的资深测试开发,我刚经历过数十个测试岗位的校招笔试和面试选拔.在 2020 年秋招面试过程中,我深深地感受到" ...
- cheerio & jQuery for server
cheerio & jQuery for server Fast, flexible & lean implementation of core jQuery designed spe ...
- C++ 0LL
C++ 0LL C plus plus L / l means long LL === long long int countDigitOne(int n) { int countr = 0; for ...
- ESLint & .eslintignore
ESLint & .eslintignore https://stackoverflow.com/questions/42250257/disable-eslint-rules-for-fol ...
- WebView & iframe
WebView & iframe https://developer.android.com/reference/android/webkit/WebView.html Web-based c ...
- Cookie 政策
Cookie 政策 合规/隐私协议 https://www.synology.cn/zh-cn/company/legal/cookie_policy Cookie Cookie 政策 生效日期:20 ...