hook

  • useEffect
  • useCallback

开始之前请注意这句话:任何优化都会增加复杂性,任何过早添加的优化都会带来风险,因为优化后的代码可能会多次更改

useEffect

相关作用:监听 & 初始化

//最简单用法useEffect(() => {//只有方法体,相当于componentDidMount和componentDidUpdate中的代码document.title = count;})//加返回值用法useEffect(() => {//添加监听事件,相当于componentDidMount和componentDidUpdate中的代码window.addEventListener('resize', onChange, false);//返回的函数用于解绑事件,相当于componentWillUnmount中的代码return () => {window.removeEventListener('resize', onChange, false)}})//加空数组参数用法useEffect(() => {// 相当于 componentDidMountwindow.addEventListener('resize', onChange, false)return () => {// 相当于 componentWillUnmountwindow.removeEventListener('resize', onChange, false)}}, []);//加监听值用法useEffect(() => {//只有当count的值发生变化,此函数才会执行console.log(`count change: count is ${count}`)}, [ count ]);

useCallback

先看一个最简单的例子:

// 用于记录 getData 调用次数
let count = 0;
function App() {const [val, setVal] = useState("");function getData() {setTimeout(()=>{setVal('new data '+count);count++;}, 500)}useEffect(()=>{getData();}, []);return (<div>{val}</div>);}

getData模拟发起网络请求。在这种场景下,没有useCallback什么事,组件本身是高内聚的。

如果涉及到组件通讯,情况就不一样了:

// 用于记录 getData 调用次数let count = 0;
function App() {const [val, setVal] = useState("");function getData() {setTimeout(() => {setVal("new data " + count);count++;}, 500);}return <Child val={val} getData={getData} />;}function Child({val, getData}) {useEffect(() => {getData();}, [getData]);return <div>{val}</div>;}

就这么轻轻松松,一个死循环就诞生了…

先来分析下这段代码的用意,Child组件是一个纯展示型组件,其业务逻辑都是通过外部传进来的,这种场景在实际开发中很常见。

再分析下代码的执行过程:

  • App渲染Child,将val和getData传进去
  • Child使用useEffect获取数据。因为对getData有依赖,于是将其加入依赖列表
  • getData执行时,调用setVal,导致App重新渲染
  • App重新渲染时生成新的getData方法,传给Child
  • Child发现getData的引用变了,又会执行getData
  • 3 -> 5 是一个死循环

如果明确getData只会执行一次,最简单的方式当然是将其从依赖列表中删除。但如果装了 hook 的lint 插件,会提示:React Hook useEffect has a missing dependency

useEffect(() => {getData();}, []);

实际情况很可能是当getData改变的时候,是需要重新获取数据的。这时就需要通过useCallback来将引用固定住:

const getData = useCallback(() => {setTimeout(() => {setVal("new data " + count);count++;}, 500);}, []);

上面例子中getData的引用永远不会变,因为他它的依赖列表是空。可以根据实际情况将依赖加进去,就能确保依赖不变的情况下,函数的引用保持不变。

还有一个要注意的是

在开始监听一个鼠标的移动的时候,想要删除这个监听不生效,由于是, 加入useState导致组件再次渲染 handleMouse 函数在次渲染, handleMouse 作为组件内的方法, 会跟着一同再次渲染, 并且在内存里, 再次渲染出的 clickFunc !== 前clickFunc.
所以removeEventListener无法解除绑定, 再次addEventListener则会绑定一个新方法.

document.addEventListener('mousemove',handleMouse,true)

解决方案 : useCallback 缓存改方法 这时候的 document.removeEventListener(‘mousemove’,handleMouse,true) 中的handleMouse 和添加中的方法就是一个了,就能删除了。

onst handleMouse= useCallback(() => {//xxxxconsole.log("clicking");}, []);

【react-hook】 useCallback相关推荐

  1. 【React深入】深入分析虚拟DOM的渲染原理和特性

    导读 React的虚拟DOM和Diff算法是React的非常重要的核心特性,这部分源码也非常复杂,理解这部分知识的原理对更深入的掌握React是非常必要的. 本来想将虚拟DOM和Diff算法放到一篇文 ...

  2. 【React组件】写一个模仿蓝湖的图片查看器

    前言 最近公司让写一个可以自由拖拽放大的图片查看器,我寻思这还不简单,一顿操作猛如虎,俩小时后: 事实证明,一旦涉及到 DOM 的变换操作,如果很多细节考虑不全,抓过来就写,那基本就凉了.于是我仔细分 ...

  3. 【React 基础】之 React 面向组件编程

    准备工作 使用 React 开发者工具调试 复习 类 相关知识 定义 class(类),代码如下: // 创建一个 Person 类 class Person {// 构造器方法constructor ...

  4. 【React 基础】之 React 基本介绍、jsx 规则、模块与组件

    React 全家桶 React 基础 React-Router 路由 PubSub + 消息管理库 Redux 集中式的状态管理 Ant-Design UI 组件库 - React 简介 官网 英文官 ...

  5. 【React学习】React更新渲染原理

    当我们调用 setState 之后发生了什么?react经历了怎样的过程将新的 state 渲染到页面上? 一次react更新,核心就是对虚拟dom进行diff,找出最少的需要变化的dom节点,然后对 ...

  6. 【React Native】iOS原生导航跳转RN页面

    上一篇介绍了React Native使用react-navigation进行导航跳转页面,现在我们介绍下原生iOS中怎么导航进一个新的React Native页面. 一.原生跳转React Nativ ...

  7. 【React Native】react-navigation导航使用方法

    目录 集成react-navigation 使用react-navigation 上一篇介绍了如何在已有iOS项目中集成React Native.这一篇我们把上一篇的demo做下拓展,添加点击电影跳转 ...

  8. 【React系列】状态(State)和生命周期

    在上一篇中写过,组件可以分为函数式组件和类组件,并且更新组件的方法也给出了通过传入ReactDOM.render()方法进行更新.但是这种方式并不能很好地进行封装成独立功能的组件,一些操作会由外部进行 ...

  9. 【react开发】使用swiper插件,loop:true时产生的问题解决方案

    这2天上班遇到的问题:react使用swiper3插件实现banner轮播,其中有个banner图有个click点击事件,而其他的是页面跳转.出现了一个问题: 就是向右滑动到该帧时的swiper,点击 ...

  10. reactnative 获取定位_【React Native】定位获取经纬度,当前城市等地址信息

    最近做React Native时,需要用到城市定位的功能,React Native中文网的定位部分中也提供了相应的方法.主要用到的方法有: 这里只需要获取到经纬度,城市等信息,持续监听的函数就不需要了 ...

最新文章

  1. “我太喜欢你了”——友情的表达方式?
  2. eclipse占用内存过大_Java性能调优学习(三)-jmap+mat分析内存溢出问题实战
  3. Numpy出现TypeError: integer argument expected, got float的分析与解决
  4. 奥南朵 | 21天提升幸福感正念冥想
  5. python函数递归 字符串反转
  6. 微型计算机机安装硬盘教程,台式机械硬盘怎么安装?机械硬盘安装图解教程(SATA固态可参考)...
  7. 电商销售数据分析(Python)
  8. 实验六 教务管理数据库的设计
  9. 捡到的苹果手机怎么解id锁_苹果手机软解和硬解的区别
  10. LAB3 PartA 用户环境与异常处理
  11. 以推理游戏开始2007年吧!
  12. win10安装Mingw,看这里!
  13. html5鼠标移过切换图片,鼠标移动到图片上切换到另一张图片,移出时又切默认图片...
  14. 架构系列---利用zookeeper 分布式锁解决缓存重建冲突实战
  15. 「儒系」产品经理:管理预期,做好增长的3个核心要素
  16. 专访宜信AI中台团队负责人王东:智慧金融时代,大数据和AI如何为业务赋能
  17. 淘宝排名查询接口,关键词排名api,淘宝商品排名查询api,淘宝关键词搜索查询接口
  18. JavaScript代码题--以及一些奇奇怪怪的发现
  19. 如何使用Django和Celery为Web构建进度栏
  20. 《Activiti/Flowable  深入BPM工作流》-如何设置local流程变量?

热门文章

  1. 软件开发中的角色分工
  2. 写给认真学习却进步缓慢的大一学生
  3. mysql-发生系统错误1067
  4. 安卓玩机搞机技巧综合资源-----不亮屏幕导资料 有屏幕锁保数据刷机等 多种方式【十五】
  5. 中兴技面+综面+面试技巧
  6. ABAP 动态控制选择屏幕 / Free Selection
  7. ffmpeg安装教程(支持10bit编码)
  8. oracle 大表删除数据后,回收空间的问题。
  9. STM32/GD32 Bootloader升级APP研究以及编程实现
  10. DNS劫持,HTTP劫持、HTTPS劫持【流量劫持】