我的react组件化开发道路(三) 懒惰+执着,驱动产品的完善

细数从开始着手写react至今已经近两个月时间了,虽然其中估计有一半时间忙工作上的事忙成狗,但是react的学习,还是犹如海绵吸水一般,获益匪浅,从一脸懵逼,到豁然开朗,再到各种踩坑、填坑中徘徊,跑得快,也应该抽空回顾下,沉淀自己,所以今天想说的,并不是各种组件的开发流程,而是在组件开发过程中遇到的坑以及解决方案。

具体项目地址:https://git.oschina.net/meichao/React-webpack

事件冒泡之坑

碰到这个问题,是在写下拉框组件的时候碰到的,问题描述:

这是完成的下拉框组件,当点击按钮时,下拉框的内容显示出来,当用户点击除了按钮部分,点击body的任何区域都会让下拉框消失(当然此时点击按钮部分也会让下拉框消失,因为此时下拉框已经出现了的),逻辑理清楚了,那么整体思路就是:需要在document.body绑定click事件,然后在按钮上绑定一个click事件,并且阻止冒泡到document.body上即可了,具体代码如下:

ComponentTool是自己写的一个工具类,bind,则为对应的元素绑定相应事件,最后是回调,unbind这刚好相反,解绑事件,然而测试的时候发现,事件还是冒泡上来了,查看元素的DOM事件可以看到:

这就有必要去看下react的事件机制了:React并不会真正的绑定事件到每一个具体的元素上,而是采用事件代理的模式:在根节点document上为每种事件添加唯一的Listener,然后通过事件的target找到真实的触发元素。这样从触发元素到顶层节点之间的所有节点如果有绑定这个事件,React都会触发对应的事件处理函数。这就是所谓的React模拟事件系统。而body是document的一个子元素,那么触发绑定在body上的事件就正常了,那么我们需要做的就是将事件绑定到document上去即可,更改了代码之后,会发现,然而并没有什么卵用,效果如下:

click还是冒泡上来了,这就头大了,难道我的冒泡没用?are you kidding me?好吧,又得得捋,stopPropagation函数只屏蔽冒泡,并不屏蔽自身的事件,这不是闹么,不过诧异的是,居然查到了stopImmediatePropagation这样的一个函数(原谅我先前的无知),stopImmediatePropagation会在调用对应的回调函数之后屏蔽对应元素对应事件所有回调函数的调用,并且禁止冒泡,OK,就它了,用起来!

报错,我的天,把event打印出来看看:

由于react代理事件的原因,这里我们得到的event仅仅是一个合成事件对象,它的主要属性如下:

想要获取浏览器事件的详情,则可以查看合成对象中的nativeEvent值:

可以看到,event.nativeEvent此时对应的是MouseEvent,即鼠标事件,代码修改为:

成功阻止事件的冒泡并且阻止了默认行为,组件能正常使用。一个简单的阻止冒泡的事件绑定,扯出了如此多的知识点~~~~。

路由资源使用require.ensure按需加载之坑

我们常规的路由设置是类似这样的(当然,其实我一开始也是这样的):

这样当我们在使用webpack这些打包工具的时候,会把所有资源一起打包进来,如果子页面很多的话,而我们的首屏却只是一个简单的页面,那么一个仅仅用到一点点资源的首屏,却要在一开始的时候去加载所有的资源,必然会卡,这对于追求首屏极致响应的前端而言,是深恶痛绝的,那么这个时候我们就可以使用require.ensure来对路由资源进行按需加载,只有当我点击某个子页面的时候,才会去加载跟这个子页面相关的资源,首屏只需要加载那些必须的资源即可,让我们来进行相应的配置:

这里做了几个简单的配置项,然后在我们的react-router引入即可,如下:

这里的route资源,就是上一张图的配置输出,因为在require.ensure中未指定每个路由资源的名字,会由其自动创建,而我们需要在webpack中设置chunkFilename:

设置完成,让我们把项目跑起来试试:

console中报了这样的一个错:

只需要如下即可去除警告:

<Router history={browserHistory} routes={route}>  
  </Router>

webpack把每个路由对应的资源单独打包出来了,命名规范就是我们在output中的chunkFilename那般,没问题,接下来让我们进入子页面:

404错误,这是为何?暂且把问题搁置,既然browserHistory不行,尝试下其他方法,将history换成hashHistory,在控制台中查看请求资源:

即使进入了子页面,资源仍然能请求到,这里就有区别了,为什么browserHistory不行而hashHistory却可以?原因在于:通过hashHistory来生成的URL不会出现这样的问题,因为它不是指向真实的路由。
而browserHistory需要服务器端做配置,路径是真实的URL,真实URL其实是指向服务器资源,比如我们经常使用的API接口,也是一个真实URL的资源路径,当通过真实URL访问网站的时候,第一次访问的是网站的域名,这个时候可以正常加载我们的网站js等文件,而用户手动刷新网页时,由于路径是指向服务器的真实路径,服务器端没有做路由配置,就会导致资源不存在,用户访问的资源不存在,返回给用户的是404错误。因为目前还没有后台,只是纯前端页面,所以暂时使用history解决了。

so?这样就完事了?可是你不觉得url里面有hash值(类似这样:http://localhost:8181/#/component/?_k=6nafo3),很丑么?别说用户受不受得了了,自己能受得了?反正我是受不了(难道是因为我是处女座,有洁癖?)。我既想用history={browserHistory},又想用require.ensure来实现按需加载(突然觉得自己蛮作的),仔细考虑问题的关键点在哪:我们使用history={browserHistory}的时候,一开始进入页面是没有任何问题的,当我们进入子页面的时候,请求的静态资源的路径出现了问题,那么我们就该从解决资源的路径入手,webpack里面有没有控制我们请求静态资源路径的方法?这个时候就需要用到我们的publicPath了,我们来看看path和publicPath的作用:

path:用来存放打包后文件的输出目录
publicPath:指定资源文件引用的目录

所以,当我的path设置成path.resolve(__dirname,'./build'),指定打包输出到该目录,所以publicPath就需要设置为”/”,表示当前路径(或者可以设置publicPath为绝对路径:http://localhost:8181/,同样可以,因为此时打包输出的build,即是网站的根目录),效果如下:

大功告成。

结语

react的组件开发过程中,确实学到了很多很多,如何让组件高内聚,低耦合,在不影响组件本身的交互前提下,还能暴露出更多的接口让用户操作等等,都值得我去全面考虑,当然,最宝贵的还是在开发过程中遇到的坑,只有踩坑了,想方设法去解决这些问题,从中学到如何去思考问题、切入问题、解决问题,才是最难能可贵的!

我还在前端的路上不断前行中!!!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom