获取中...

-

Just a minute...

记录一些刚写react踩过的坑吧,想到多少就写多少

从一个工作中的需求开始

有个需求是,点击按钮出来一个弹窗。本来弹窗有个关闭按钮,但是UED在视觉稿上面加了行字,“点击关闭按钮或弹窗外的其他地方,关闭弹窗”。我想了想,合理,避免有些奇怪的操作使得弹窗没关掉。实现的方法就是监听点击事件呗,然后判断点击的是哪,如果弹窗是打开的,并且点击的地方不在弹窗里,就把弹窗关掉。

具体代码我直接CSDN找了一个,好用的。通过createref来获取dom,对document使用addEventListener,监听点击的event.target,判断和弹窗dom的关系就可以了。本来是个挺简单的事,但是我用了之后发现,本来那个打开弹窗的按钮也不好用了。后来发现,因为那个按钮也是弹窗之外,所以弹窗打开就马上关闭了。一开始没想到事件捕获和冒泡,我想当然地以为,应该先触发document的点击事件,这个时候弹窗没出现,所以无事发生,然后再触发按钮的点击事件,打开弹窗。这和实际的结果并不相符。

我调试的时候发现,点击按钮后总是先打开弹窗,再触发document的点击事件,把弹窗关上。我当时想的解决办法是,把点击按钮的onClick外面包一层setTimeout,延迟0。将打开按钮的操作改成了异步事件,根据事件循环机制,异步会在同步代码执行完毕一轮之后,再去执行,这样就保证了打开弹窗的操作,一定在判断点击位置然后关闭弹窗之后。这样就能正常打开弹窗了。

其他的解决方法

后来我下班之后,又继续研究这个问题,这时候才想明白,之前两个点击事件的执行顺序不对,是因为事件的捕获和冒泡机制。原来onClick和addEventListener默认都是冒泡,所以执行顺序就是先最低层级的dom元素,最后是document,就出问题了。然而addEventListener的第三个参数改成true,就变成捕获阶段了,这样就对了。然后我就想,写个简单的demo来验证一下。

问题并不简单

然后就出问题了,我用vite脚手架建了个基本的react demo,然后用函数式组件,直接在函数体内部(没有使用useEffect)完成了对document添加点击响应事件的操作,然后我发现,怎么每回一点击屏幕,都会触发两次点击事件。我寻思为啥会触发两次呢?我顿时就想到,有可能是添加了两个点击响应事件。如果像我这样直接在函数体内部,不使用useEffect把addEventListener添加到一个元素上,然后组件重新渲染,函数重新执行,就会对一个事件添加多个响应函数。当然本身或者子组件除外,因为重新渲染的时候点击事件也没了。

函数式编程与副作用

但是我这显然是没有重新渲染的,一个连state都没有的根组件咋可能会去重新渲染。但是我通过chrome的api,getEventListeners查看,发现确实有2个eventListener。然后我试着加了个state,然后改变state,发现eventListener变成4个了,再改变state,变成6个了。这更加说明了每次组件重新渲染的时候,都渲染了两次。后来我去查了一些,发现是react18的严格模式下,开发环境的时候,组件的渲染会执行两遍,就是为了让开发者发现不应该出现的副作用。就比如我的这个添加eventListener应该写在useEffect内部,并且通过useEffect的return,清除副作用。这也给我提了个醒。

函数式组件写起来很方便,很简便。但是和类组件不同,类组件重新渲染只会重新执行render函数,而函数式组件是通篇执行。所以函数式组件更要注意副作用,一定要写在useEffect里面,并且做好清除工作,比如remove响应事件。然后我感觉,我对函数式编程和副作用的理解还有待加强。只能说这一个小需求,让我收获了很多。虽然后来mentor跟我说这种不影响整体功能的需求没必要花时间,但是我认为这次我的尝试,还是让我对react有了更深一步的了解。

相关文章
评论
分享
  • 聊聊react与函数式编程

    react不是魔法 今天我想来聊一聊函数式编程,和它在react中的体现。 何为函数式编程我们可以把函数式编程理解成一种范式,一个规范。纯函数是函数式编程的关键概念,函数式编程希望我们尽可能多地使用纯函数。正是依赖于纯函数的特点,...

    聊聊react与函数式编程
  • 使用react的一些心得与感想

    刚忙完公司的新人训练营,9个人的团队2周完成一个小项目。我负责用remax开发一个微信小程序。remax就是蚂蚁的一个开源框架,让开发者能用react的语法去开发微信小程序。开发体验整体来讲非常不错,感觉也加深了我对react的理解...

    使用react的一些心得与感想
  • 一些部署相关的名词解释

    毕业刚入职,看到公司的各种发布,部署平台,眼花缭乱,看文档的过程中也看到了很多不懂的名词,了解了之后做一下记录 名词解释 serverless: 字面意思是“无服务器”,即开发者(开发公司)不用自己的机房服务器,采用云服务器厂商提...

    一些部署相关的名词解释
  • 动手实现react-ssr 2

    仓库链接:本篇代码 运行方法参考readme,请使用pnpm,因为本次使用的rspack尚未推出1.0版本,预计后续可能会有很多breakchange,所以lock文件至关重要,而我只上传了pnpm的lock,非常抱歉。 环境:no...

    动手实现react-ssr 2
  • 动手实现react ssr

    关于ssr相关的介绍,可以移步之前的一篇博文,本文不再赘述 日常工作中,我们可能都接触过ssr,不过我们可能通常是借助于框架(例如Next.js)的支持来完成ssr。今天我想尝试,摆脱高度封装的前端框架,只依赖react相关的库,来实...

    动手实现react ssr
  • 从invalid hook call报错说到npm install相关

    遇到了invalid hook call报错上周,业务下游的同事反馈了一个生产问题,说我们传的值有问题,领导让我帮忙排查一下。我最近一直没做那个项目相关的需求,打开那个项目切到release分支,拉代码,npm i然后启动,结果就白屏...

    从invalid hook call报错说到npm install相关
  • React中副作用的执行时机

    为什么一定要useEffect?之前看到过,说不要把副作用直接写在函数式组件的函数体内,需要用useEffect把副作用包裹起来。我当时的理解就是,函数组件重新渲染的话,整个函数都会被执行一遍。如果我就想让一个副作用,每次组件渲染都重...

    React中副作用的执行时机
  • 基于tapable来模拟webpack插件机制

    前两天看到ByteFE公众号发了篇文章,从源码去讲webpack。我之前也从很多方面去学习webpack,只是源码一直没太看得进去,这一次我想仔细地读一读。 简要介绍tapable说实话,之前看webpack源码一直没看的太懂,...

    基于tapable来模拟webpack插件机制
  • 深入js——作用域,作用域链,执行栈(一)

    最近在补js基础。当初自学js的时候,总是感觉学的不扎实。只能说不去上手,再怎么死读书,也理解不了。积累了经验,然后自己去思考,这个时候再去看理论,就容易理解了。 感觉工作一年以来,确实学到了很多,但是过于专注于应用方面的知识,反倒...

    深入js——作用域,作用域链,执行栈(一)
  • webpack运行时代码简要分析

    开个坑,主要也是怕自己后面忘了 简单写写,有空了补上 __webpack_modules是一个数组,每个元素都是一个函数,函数接受三个参数:第一个参数module好像没用到,第二个是一个对象(会把本模块要导出的属性,赋值给这个对象),...

    webpack运行时代码简要分析
Please check the parameter of comment in config.yml of hexo-theme-Annie!