文章目录
- React综合技术总汇
- 理论篇
- 1.react理解
- 2.react生命周期
- 3.react新生命周期取代了哪些?为什么?
- 4.Fiber架构的理解?解决了什么问题
- 5.说说redux的实现原理是什么,写出核心代码
- 6.React 的事件合成?
- 7.React组件之间如何通信
- 8.setState 是同步,还是异步的?
- 9.React render方法的原理,在什么时候会触发?
- 10.说说React生命周期中有哪些坑?如何避免?
- 11.说说Real diff算法是怎么运作的?
- 12.调和阶段setState干了什么?
- 13.使用 redux 有哪些原则?
- 14.React事件代理机制
- 15.redux-thunk和redux-saga区别
- 16.React的props.children使用map函数来遍历会收到异常显示,为什么?应该 如何遍历?
- 17. redux中同步action与异步action最大的区别是什么
- 18. 说说你对受控组件和非受控组件的理解?应用场景?
- 19. 说说react diff的原理是什么
- 20.什么是强缓存和协商缓存
- 21.什么是面向对象编程及面向过程编程,它们的异同和优缺点
- 22. 说说你对@reduxjs/toolkit的理解?和react-redux有什么区别
- 23.window.onload和$(document).ready
- 24 如何通过原生js实现一个节流函数和防抖函数
- 25.说说webpack中常见的loader?解决了什么问题
- 26. 现在要你完成一个Dialog组件,说说你设计的思路?它应该有什么功能?
React综合技术总汇
理论篇
1.react理解
React,用于构建用户界面的 JavaScript 库,只提供了 UI 层面的解决方案 ,是渐进式框架
特性: JSX 语法 , 单向数据绑定 , 虚拟 DOM , 声明式编程 ,组件化开发
2.react生命周期
组件挂载时
当组件实例被创建并插入DOM时,其生命周期调用顺序如下:
constructor()
static getDerivedStateFromProps()
render()
componentDidMount()
组件更新时
当组件的props或state发生变化时会触发更新。组件更新的生命周期调用顺序如下:
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
组件卸载时
当组件从DOM中移除时会调用如下方法
componentWillUnmount()
3.react新生命周期取代了哪些?为什么?
React 新的生命周期方法主要是为了支持 Fiber 架构中的三个新概念而设计的: fiber节点,异步渲染,可中断性
-
getDerivedStateFromProps(静态方法) 取代了componentWillMount和 componentWillReceiveProps
-
getSnapshotBeforeUpdate 取代了componentWillUpdate
-
getDerivedStateFromProps中禁止了组件去访问 this.props,
-
由于 this.props 可能在任何时刻发生变化,所以计算出来的 state 对象可能会与旧的 state 对象相同,从而导致状态更新无效和不必要的组件重新渲染。
-
在 getDerivedStateFromProps 方法中应该始终使用参数中的 nextProps,而不是 this.props。这样可以保证组件状态的计算是基于最新的 props,从而避免了状态更新无效和渲染性能的问题。
-
getSnapshotBeforeUpdate 方法是在组件的 render 方法被调用后,在更新 DOM 之前被调用的 ,
-
也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素信息是可以保证与componentDidUpdate 中一致的。
4.Fiber架构的理解?解决了什么问题
在 React 16 之前,VirtualDOM 的更新采用的是Stack架构实现的,也就是循环递归方式。不过,这种对比方式有明显的缺陷,就是一旦任务开始进行就无法中断,如果遇到应用中组件数量比较庞大,那么VirtualDOM 的层级就会比较深,带来的结果就是主线程被长期占用,进而阻塞渲染、造成卡顿现象。
fiber:为了避免出现卡顿等问题,我们必须保障在执行更新操作时计算时不能超过16ms,如果超过16ms,就需要先暂停,让给浏览器进行渲染,后续再继续执行更新计算。而Fiber架构就是为了支持“可中断渲染”而创建的。 解决了react在渲染大量dom节点出现丢帧的问题
从架构角度:fiber是对react核心算法的重写(调和过程)
从编码角度:fiber是react内部定义的一种数据结构,是fiber树结构的节点单位,react16新架构下的虚拟dom
主要操作:
为每个增加了优先级,优先级高的任务可以中断低优先级的任务。然后再重新,注意是重新执行优先级低的任务
增加了异步任务,调用requestIdleCallback api,浏览器空闲的时候执行
dom diff树变成了链表,一个dom对应两个fiber(一个链表),对应两个队列,这都是为找到被中断的任务,重新执行
在 Fiber 架构中,React 将组件的更新过程分为两个阶段:reconciliation 和 commit。其中 reconciliation 阶段主要负责计算出更新后的 Virtual DOM 树,并确定哪些组件需要进行重新渲染,而 commit 阶段则负责将 Virtual DOM 树的变化映射到真实的 DOM 上。
总结:相比传统的Stack架构,Fiber 将工作划分为多个工作单元,每个工作单元在执行完成后依据剩余时间决定是否让出控制权给浏览器执行渲染。 并且它设置每个工作单元的优先级,暂停、重用和中止工作单元。 每个Fiber节点都是fiber tree上的一个节点,通过子、兄弟和返回引用连接,形成一个完整的fiber tree
5.说说redux的实现原理是什么,写出核心代码
- 将应用的状态统一放到state中,由store来管理state。
- reducer的作用是 返回一个新的state去更新store中对用的state。
- 按redux的原则,UI层每一次状态的改变都应通过action去触发,action传入对应的reducer 中
- reducer返回一个新的state更新store中存放的state,这样就完成了一次状态的更新
- subscribe是为store订阅监听函数,这些订阅后的监听函数是在每一次dipatch发起后依次执行
- 可以添加中间件对提交的dispatch进行重写
- 核心API
- createStore 创建仓库,接受reducer作为参数
- bindActionCreator 绑定store.dispatch和action 的关系
- combineReducers 合并多个reducers
- applyMiddleware 洋葱模型的中间件,介于dispatch和action之间,重写dispatch
- compose 整合多个中间件
6.React 的事件合成?
- 所有事件都是委托在id = root的DOM元素中(网上很多说是在document中,17版本不是了);
- 在应用中所有节点的事件监听其实都是在id = root的DOM元素中触发;
- React自身实现了一套事件冒泡捕获机制;
- React实现了合成事件SyntheticEvent;
- React在17版本不再使用事件池了(网上很多说使用了对象池来管理合成事件对象的创建销毁,那是16版本及之前);
- 事件一旦在id = root的DOM元素中委托,其实是一直在触发的,只是没有绑定对应的回调函数;
7.React组件之间如何通信
1.父组件向子组件通讯:
父组件可以向子组件传入props的方式,向子组件进行通讯。
2.子组件向父组件通讯:
props+回调的方式,父组件向子组件传递props进行通讯,此props为作用域为父组件自身的函数,子组件调用该函数,将子组件想要传递的信息,作为参数,传递到⽗组件的作⽤域中。
3.兄弟组件通信:
兄弟组件之间的传递,则父组件作为中间层来实现数据的互通,通过使用父组件传递
例:组件A – 传值 --> 父组件 – 传值 --> 组件B
4.跨层级通讯:
Context 设计⽬的是为了共享那些对于⼀个
组件树⽽⾔是“全局”的数据,
使用context提供了组件之间通讯的一种方式,可以共享数据,其他数据都能读取对应的数据
例如当前认证的⽤户、主题或⾸选语⾔,对于跨越多层的全局数据通过 Context 通信再适合不过。
5.发布订阅者模式:
发布者发布事件,订阅者监听事件并做出反应,我们可以通过引⼊event模块进⾏通信。
6.全局状态管理工具:
借助Redux或者Mobx等全局状态管理⼯具进⾏通信,这种⼯具会维护⼀个全局状态中⼼Store,并根据不同的事件产⽣新的状态。
8.setState 是同步,还是异步的?
- react18之前:setState在不同情况下可以表现为异步或同步。在Promise的状态更新、js原生事件、setTimeout、setInterval…中是同步的。在react的合成事件中,是异步的。
- react18之后: setState都会表现为异步(即批处理)。
- 解释react18之前:
- 原因:在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。
9.React render方法的原理,在什么时候会触发?
- 原理:
在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件
render函数中的jsx语句会被编译成我们熟悉的js代码,在render过程中,react将新调用的render函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比较,更新dom树 - 触发机:
类组件调用 setState 修改状态
函数组件通过useState hook修改状态
一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行render方法,一旦父组件发生渲染,子组件也会渲染
10.说说React生命周期中有哪些坑?如何避免?
- getDerivedStateFromProps 容易编写反模式代码,使受控组件和非受控组件区分模糊
- componentWillMount 在 React 中已被标记弃用,不推荐使用,主要的原因是因为新的异步架构会导致它被多次调用,所以网络请求以及事件绑定应该放到 componentDidMount 中
- componentWillReceiveProps 同样也被标记弃用,被 getDerivedStateFromProps 所取代,主要原因是性能问题。
- shouldComponentUpdate 通过返回 true 或者 false 来确定是否需要触发新的渲染。主要用于性能优化。
- componentWillUpdate 同样是由于新的异步渲染机制,而被标记废弃,不推荐使用,原先的逻辑可结合 getSnapshotBeforeUpdate 与 componentDidUpdate 改造使用。
- 如果在 componentWillUnmount 函数中忘记解除事件绑定,取消定时器等清理操作,容易引发 bug。
- 如果没有添加错误边界处理,当渲染发生异常时,用户将会看到一个无法操作的白屏,所以一定要添加
11.说说Real diff算法是怎么运作的?
- Diff算法是虚拟DOM的一个必然结果,它是通过新旧DOM的对比,将在不更新页面的情况下,将需要内容局部更新
- Diff算法遵循深度优先,同层比较的原则
- react中diff算法主要遵循三个层级的策略:
tree层级:DOM节点的跨层级操作不做优化,只对相同层节点进行比较,只有删除创建操作,没有移动操作
conponent 层级:如果是同一类的组件,则会继续往下进行diff运算,如果不是则直接删除组件下的所有子节点,创建新的
element 层级:对于比较同一层级的节点们,每个节点在对应的层级用唯一的key作为标识,通过key知道节点的变化,移动旧集合节点位置,更新为新集合节点位置
12.调和阶段setState干了什么?
- 代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。
- 经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面;
- 在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染;
在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。
13.使用 redux 有哪些原则?
- 单一数据源:整个应用的全局 state 被存储在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。
- State 是只读的:唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事情的普通对象。
- 使用纯函数来执行修改:为了描述 action 如何改变 state tree,你需要编写纯的 reducers。
14.React事件代理机制
React 并不会把所有的处理函数直接绑定在真实的节点上。而是把所有的事件绑定到结构的最外层,使用一个统一的事件监听器,这个事件监听器上维持了一个映射来保存所有组件内部的事件监听和处理函数。
- 所有事件都是委托在id = root的DOM元素中(网上很多说是在document中,17版本不是了);
- 在应用中所有节点的事件监听其实都是在id = root的DOM元素中触发;
- React自身实现了一套事件冒泡捕获机制;
- React实现了合成事件SyntheticEvent;
- React在17版本不再使用事件池了(网上很多说使用了对象池来管理合成事件对象的创建销毁,那是16版本及之前);
- 事件一旦在id = root的DOM元素中委托,其实是一直在触发的,只是没有绑定对应的回调函数;
15.redux-thunk和redux-saga区别
1.redux-thunk 的设计思路是将异步逻辑封装到“thunk”函数中,这个函数接收 dispatch 方法作为参数,并返回一个带有回调函数的函数。这个回调函数在异步操作完成后被调用,然后再通过 dispatch 方法触发一个 action,更新 Redux store 中的数据。redux-thunk 适合用于处理简单的异步逻辑,比如发送 AJAX 请求或者获取本地存储数据等。 没有拓展api
2.redux-saga 则采用了另外一种设计思路,它使用了 ES6 的 generator 函数来实现异步逻辑的管理。在 redux-saga 中,使用 generator 函数定义一个 saga,它可以监听一个或多个 action,并在相应的 action 被触发后执行一些副作用,比如发送 AJAX 请求、触发其他 action 等。redux-saga 还提供了一些辅助函数和特性(api),比如 takeLatest、put、call 等,使得开发者可以更加方便地管理异步流程,处理错误和取消请求等。
16.React的props.children使用map函数来遍历会收到异常显示,为什么?应该 如何遍历?
在reactJS 中 props.children 不一定是数组,
有三种可能 :
1当前组件没有子节点数据类型就是undefined,
2有一个子节点数据类型就是object 。
3 有多个子节点的时候才会是array ,只有在多个节点的时候才可以直接调用map方法,react资深提供了一个react.children.map()方法,可以安全遍历子节点对象。
应该怎么样?
React 提供了工具方法 React.Children 来处理 props.children。
React.Children中的方法
-
React.Children.map
object React.Children.map(object children, function fn)
遍历 props.children ,在每一个子节点上调用 fn 函数。 -
React.Children.forEach
React.Children.forEach(object children, function fn)
类似于 React.Children.map(),但是不返回对象。 -
React.Children.count
number React.Children.count(object children)
返回 children 当中的组件总数。 -
React.Children.only
object React.Children.only(object children)
返回 children 中仅有的子节点。如果在 props.children 传入多个子节点,将会抛出异常
17. redux中同步action与异步action最大的区别是什么
同步action:执行了dispatch函数之后,对应的reducer纯函数立即得到执行,reducer执行完了之后,state立即就改变了,此时用store.getState函数,取到的是最新的state值;
异步action:原则上redux并没有提供异步action的处理方案,异步的action需要依赖第三方的中间件解决(如redux-thunk),dispatch了一个异步action(本质上是dispatch的一个函数)之后,目标state并不会立即响应,而是要看异步函数内部的逻辑,来决定state什么时候响应。
18. 说说你对受控组件和非受控组件的理解?应用场景?
一、受控组件
1.受控组件的概念:
在React中,可变状态通常保存在组件的状态属性中,并且只能使用setState()进行更新,而呈现表单的React组件也控制着在后续用户输入时该表单中发生的情况,以这种由React控制的输入表单元素而改变其值的方式,成为受控组件。
2.受控组件更新state的流程:
a.通过初始state中设置表单的默认值
b.每当表单的值发生变化时,调用onChange事件处理器
c.事件处理器通过事件对象event拿到改变后的状态,并更新组件的state
d.一旦通过setState方法更新state,就会触发视图重新渲染,完成表单组件的更新
二、非受控组件
1.非受控组件:
非受控组件指的是表单数据由DOM本身处理。即不受setState()的控制,与传统的HTML表单输入相似,input输入值即显示的最新值。
2.非受控组件的使用:
在非受控组件中,由于无法直接使用js中dom操作,所以我们可以使用ref来从DOM中获得表单值。非受控组件在底层实现时是在其内部维护了自己的状态state,这样表现出用户输入任何值都能反映到元素上。
三、受控组件与非受控组件的区别
1.受控组件
a.受控组件依赖于状态(它是通过setState来更新表单数据,可以对表单进行操作)
b.受控组件的修改会实时映射到状态值上,此时可以对输入的内容进行校验
c.受控组件只用继承React.Component才会有状态(这个区别自己还是一知半解)
d.受控组件必须要在表单上使用onChange事件来绑定对应的事件(表单元素通过onChange发生改变时触发setState更新状态)
2.非受控组件
a.非受控组件不受状态的控制
b.非受控组件获取数据就相当于操作DOM(通过ref来获取数据)
c.非受控组件可以很容易与第三方组件结合,更容易同时集成React和非React代码
四、如何选择受控组件还是非受控组件
1、受控组件使用场景:
一般用在需要动态设置其初始值的情况。例如:某些form表单信息编辑时,input表单元素需要初始显示服务器返回的某个值然后进行编辑。
2、非受控组件使用场景:
一般用于无任何动态初始值信息的情况。例如:form表单创建信息时,input表单元素都没有初始值,需要用户输入的情况
19. 说说react diff的原理是什么
react中diff算法主要遵循三个层级的策略:
tree层级
conponent 层级
element 层级
1.tree层级
DOM节点跨层级的操作不做优化,只会对相同层级的节点进行比较
2conponent层级
如果是同一个类的组件,则会继续往下diff运算,如果不是一个类的组件,那么直接删除这个组件下的所有子节点,创建新的
3element层级
对于比较同一层级的节点们,每个节点在对应的层级用唯一的key作为标识
提供了 3 种节点操作,分别为 INSERT_MARKUP(插入)、MOVE_EXISTING (移动)和 REMOVE_NODE (删除)
20.什么是强缓存和协商缓存
强制缓存:根据Expires(response header里的过期时间)判断,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存,并不会向服务端发起请求,展示为200状态。
协商缓存:客户端向服务端发送带有If-None-Match和If-Modified-Since的请求进行协商判断,如果资源没有变化继续使用本地缓存,记录为304状态;如果资源发生变化,服务端响应数据,记录为200状态。
21.什么是面向对象编程及面向过程编程,它们的异同和优缺点
面向过程(Procedure Oriented 简称 PO):把事情拆分成几个步骤(相当于拆分成一个个的方法和数据),然后按照一定的顺序执行。
面向对象(Object Oriented 简称 OO):面向对象会把事物抽象成对象的概念,先抽象出对象,然后给对象赋一些属性和方法,然后让每个对象去执行自己的方法。
面向过程:
优点:效率高,因为不需要实例化对象。
缺点:耦合度高,扩展性差,不易维护(例如:每个步骤都要有,不然就不行)
面向对象:
优点:耦合低(易复用),扩展性强,易维护,由于面向对象有封装、继承、多态性的特点,可以设计出低耦合的系统,使系统更加灵活、更加易于维护。
缺点:效率比面向过程低。
22. 说说你对@reduxjs/toolkit的理解?和react-redux有什么区别
什么是reduxjs/toolkit?
Redux Toolkit 是我们官方推荐的编写 Redux 逻辑的方法。它围绕 Redux 核心,并包含我们认为对于构建 Redux 应用必不可少的软件包和功能。Redux Toolkit 建立在我们建议的最佳实践中,简化了大多数 Redux 任务,防止了常见错误,并使编写 Redux 应用程序更加容易。
React-redux是官方react UI绑定层,允许React组件从redux存储中读取数据,并将操作分派到存储以更新的状态。提供了connect,Provider等API,帮助我们连接react和redux,实现的逻辑会更加的严谨高效。
@reduxjs/tookit是对Redux的二次封装,开箱即用的一个高效的Redux开发工具,使得创建store,更新store
区别
1、reduxjs/tookit相对于react-redux来说比较方便,集成了redux-devtools-extension,不需要额外的配置,非常方便
2、reduxjs/tookit集成immutable-js的功能,不需要安装配置使用,提升了开发效率
3、reduxjs/tookit集成了redux-thunk的功能
4、reduxjs/tookit将types、actions、reducers放在一起组成了全新的slices,简化了我们的使用
23.window.onload和$(document).ready
1、对页面加载的认识
一般情况下,一个页面的相应加载顺序是:域名解析——>加载html——>加载js和css——>加载图片等其他信息
2、关于document.ready()
执行时机:在DOM完全就绪时就可以被调用。
多次使用:在同一个文件中多次使用,一次调用。
理解:document.ready()的意思是在DOM加载完成之后执行ready()方法中的代码,换句话说,这个方法的本意是为了让代码的执行时间是在DOM加载完成之后才开始执行。
3、关于document.onload()
执行时机:在网页中所有元素(包括元素的所有关联文件)完全加载到浏览器后才执行,即JavaScript此时可以访问网页中的所有元素。
多次执行:JavaScript的onload事件一次只能保存对一个函数的引用,他会自动调用最后面的函数覆盖前面的函数
4、document.ready和window.onload的区别
document.ready和window.onload的区别——JavaScript文档加载完成事件。
页面加载完成有两种事件:
一是ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件)。
二是onload,指示页面包含图片等文件在内的所有元素都加载完成。
5、为什么要使用document.ready()或者document.onload()
$(document).ready() 里的代码是在页面内容都加载完才执行的,如果把代码直接写到script标签里,当页面加载完这个script标签就会执行里边的代码了,此时如果你标签里执行的代码调用了当前还没加载过来的代码或者dom,那么就会报错,当然如果你把script标签放到页面最后面那么就没问题了,此时和ready效果一样。
6、document.ready()的使用场景
点击段落,此段落隐藏
24 如何通过原生js实现一个节流函数和防抖函数
1.原生js实现防抖
什么是防抖?
事件触发后,若n秒内该事件没有再次发生,则执行这个函数,如果n秒内该事件再次发生,则重新开始计时。
防抖 事件不立即触发,N秒内只能被触发一次
let btn = document.querySelector('button');
function write(){
console.log('已经成功实现防抖');
}
const fd = function(fn,deplay){
let timer;
return function(){
const that = this;
const arg = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
fn.apply(that,arg)
},deplay)
}
}
btn.addEventListener('click',fd(write ,1000));
2.原生js实现节流
什么是节流 ?
节流当指定时间持续触发某个事件时,该事件只会执行首次触发事件,
也就是说指定时间内只会触发一次。
原生实现节流的方式有两种:定时器节流(不会立即触发)和时间戳节流(立即触发)
定时器节流 (不会立即触发) ---- 个人不建议使用
不立即触发,N秒内只能被触发一次
const btn = document.querySelector('button');
function write() {
console.log('这是定时器节流');
}
const jl = function (fn, deplay) {
let timer;
return function () {
let content = this;
let ar = arguments;
if (timer) {
return;
}
timer = setTimeout(function () {
fn.apply(content, arguments);
timer = null;
}, deplay);
}
}
btn.addEventListener('click', jl(write, 1000));
``
```javascript
时间戳节流(立即触发) --- 推荐使用
立即触发,但下次允许触发在N秒后(N秒内无法被触发)
let btn = document.getElementById("btn")
function write() {
console.log('这是时间戳节流');
}
function throttle(fn, waiting) {
// 上一次的执行时间
let previous = 0;
return function (...args) {
// 当前时间
let now = +new Date();
if (now - previous > waiting) {
previous = now;
fn.apply(this, args);
}
}
}
btn.addEventListener('click', throttle(write, 1000));
25.说说webpack中常见的loader?解决了什么问题
一、webpack是什么
webpack做的事情,仅仅是分析出各种模块的依赖关系,然后形成资源列表,最终打包生成到指定的文件中。
二、loader是什么
loader的作用说白了就是将一种形式的代码通过逻辑转变成另一种形式的代码,转换后的代码webpack就能识别了。
三、常见的loader:
image-loader:加载并且压缩图片文件
css-loader:帮助webpack打包处理css文件,使用css-loader必须要配合使用style-loader
style-loader:用于将css编译完成的样式,挂载到页面的style标签上。但是要注意loader执行顺序,style-loader要放在第一位,loader都是从后往前执行
babel-loader:把 ES6 转换成 ES5
sass-loader: css预处理器,能更好的编写css
postcss-loader: 用于补充css样式在各种浏览器的前缀,很方便,不需要手动写了
eslint-loader:用于检查代码是否符合规范,是否存在语法错误
url-loader:处理图片类型资源,可以根据图片的大小进行不同的操作,如果图片大小大于指定大小,则将图片进行资源打包,否则将图片转换为base64格式字符串,再把这个字符串打包到 JS文件里。
特性
1.loader 可以是同步的,也可以是异步的
2.loader 运行在 Node.js 中,并且能够执行任何操作
除了常见的通过 package.json 的 main 来将一个 npm 模块导出为 loader,还可以在 module.rules 中使用 loader 字段直接引用一个模块
插件(plugin)可以为 loader 带来更多特性
3.loader 能够产生额外的任意文件
4.可以通过 loader 的预处理函数,为 JavaScript 生态系统提供更多能力。用户现在可以更加灵活地引入细粒度逻辑,例如:压缩、打包、语言翻译和更多其他特性
5.loader支持链式调用
26. 现在要你完成一个Dialog组件,说说你设计的思路?它应该有什么功能?
1.该组件需要提供hook指定渲染位置,默认渲染在body下面。
2.然后改组件可以指定外层样式,如宽度等
3.组件外层还需要一层mask来遮住底层内容,点击mask可以执行传进来的onCancel函数关闭Dialog。
4.另外组件是可控的,需要外层传入visible表示是否可见。
5.然后Dialog可能需要自定义头head和底部footer,默认有头部和底部,底部有一个确认按钮和取消按钮,确认按钮会执行外部传进来的onOk事件,然后取消按钮会执行外部传进来的onCancel事件。
6.当组件的visible为true时候,设置body的overflow为hidden,隐藏body的滚动条,反之显示滚动条。
7.组件高度可能大于页面高度,组件内部需要滚动条。
8.只有组件的visible有变化且为ture时候,才重渲染组件内的所有内容