1、为什么选择框架?
组件化:使我们的工程易于维护,容易拓展
分层的设计:mvvm框架等等使我们的代码解耦易于读写,视图数据分离
开发效率:底层封装好了具体的方法来更新DOM,而非我们手动操作,解放了开发者的手动DOM成本,提高开发效率。
状态管理的优化:例如vuex readux的使用
现在的框架基本都有生命周期,方便我们在各个周期进行操作,比js的混杂模式更加的方便,清晰
2、虚dom的优劣
优点
保证性能下限: 虚拟DOM可以经过diff找出最小差异,然后批量进行patch,这种操作虽然比不上手动优化,但是比起粗暴的DOM操作性能要好很多,因此虚拟DOM可以保证性能下限
无需手动操作DOM: 虚拟DOM的diff和patch都是在一次更新中自动进行的,我们无需手动操作DOM,极大提高开发效率
跨平台: 虚拟DOM本质上是JavaScript对象,而DOM与平台强相关,相比之下虚拟DOM可以进行更方便地跨平台操作,例如服务器渲染、移动端开发等等
3、react的生命周期
React 16之后有三个生命周期被废弃(但并未删除)
componentWillMount
componentWillReceiveProps
componentWillUpdate
官方计划在17版本完全删除这三个函数,只保留UNSAVE_前缀的三个函数,目的是为了向下兼容,但是对于开发者而言应该尽量避免使用他们,而是使用新增的生命周期函数替代它们
目前React 16.8 +的生命周期分为三个阶段,分别是挂载阶段、更新阶段、卸载阶段
挂载阶段:
constructor: 构造函数,最先被执行,我们通常在构造函数里初始化state对象或者给自定义方法绑定this
getDerivedStateFromProps: static getDerivedStateFromProps(nextProps, prevState),这是个静态方法,当我们接收到新的属性想去修改我们state,可以使用getDerivedStateFromProps
render: render函数是纯函数,只返回需要渲染的东西,不应该包含其它的业务逻辑,可以返回原生的DOM、React组件、Fragment、Portals、字符串和数字、Boolean和null等内容
componentDidMount: 组件装载之后调用,此时我们可以获取到DOM节点并操作,比如对canvas,svg的操作,服务器请求,订阅都可以写在这个里面,但是记得在componentWillUnmount中取消订阅
更新阶段:
getDerivedStateFromProps: 此方法在更新个挂载阶段都可能会调用
shouldComponentUpdate: shouldComponentUpdate(nextProps, nextState),有两个参数nextProps和nextState,表示新的属性和变化之后的state,返回一个布尔值,true表示会触发重新渲染,false表示不会触发重新渲染,默认返回true,我们通常利用此生命周期来优化React程序性能
render: 更新阶段也会触发此生命周期
getSnapshotBeforeUpdate: getSnapshotBeforeUpdate(prevProps, prevState),这个方法在render之后,componentDidUpdate之前调用,有两个参数prevProps和prevState,表示之前的属性和之前的state,这个函数有一个返回值,会作为第三个参数传给componentDidUpdate,如果你不想要返回值,可以返回null,此生命周期必须与componentDidUpdate搭配使用
componentDidUpdate: componentDidUpdate(prevProps, prevState, snapshot),该方法在getSnapshotBeforeUpdate方法之后被调用,有三个参数prevProps,prevState,snapshot,表示之前的props,之前的state,和snapshot。第三个参数是getSnapshotBeforeUpdate返回的,如果触发某些回调函数时需要用到 DOM 元素的状态,则将对比或计算的过程迁移至 getSnapshotBeforeUpdate,然后在 componentDidUpdate 中统一触发回调或更新状态。
卸载阶段:
componentWillUnmount: 当我们的组件被卸载或者销毁了就会调用,我们可以在这个函数里去清除一些定时器,取消网络请求,清理无效的DOM元素等垃圾清理工作
4、React的请求应该放在哪个生命周期中?
React的异步请求到底应该放在哪个生命周期里,有人认为在componentWillMount中可以提前进行异步请求,避免白屏,其实这个观点是有问题的.
由于JavaScript中异步事件的性质,当您启动API调用时,浏览器会在此期间返回执行其他工作。当React渲染一个组件时,它不会等待componentWillMount它完成任何事情 - React继续前进并继续render,没有办法“暂停”渲染以等待数据到达。
而且在componentWillMount请求会有一系列潜在的问题,首先,在服务器渲染时,如果在 componentWillMount 里获取数据,fetch data会执行两次,一次在服务端一次在客户端,这造成了多余的请求,其次,在React 16进行React Fiber重写后,componentWillMount可能在一次渲染中多次调用.
目前官方推荐的异步请求是在componentDidmount中进行.
如果有特殊需求需要提前请求,也可以在特殊情况下在constructor中请求:
react 17之后componentWillMount会被废弃,仅仅保留UNSAFE_componentWillMount
5、setstate是同步还是异步的?(合成事件和钩子函数中是“异步”)
6、react组件间的通信策略
7、关于组件复用点击https://github.com/Advanced-Interview-Question/front-end-interview/blob/master/docs/guide/abstract.md
8、对于时间分片的理解
React 在渲染(render)的时候,不会阻塞现在的线程
如果你的设备足够快,你会感觉渲染是同步的
如果你设备非常慢,你会感觉还算是灵敏的
虽然是异步渲染,但是你将会看到完整的渲染,而不是一个组件一行行的渲染出来
同样书写组件的方式
时间分片正是基于可随时打断、重启的Fiber架构,可打断当前任务,优先处理紧急且重要的任务,保证页面的流畅运行.
9、关于redux
这个是redux的过程(数据单向流动),处理异步的时候引入中间件,redux-thunk,redux-saga等等
首先,用户(通过View)发出Action,发出方式就用到了dispatch方法。
然后,Store自动调用Reducer,并且传入两个参数:当前State和收到的Action,Reducer会返回新的State
State一旦有变化,Store就会调用监听函数,来更新View。
关于react-redux
Provider: Provider的作用是从最外部封装了整个应用,并向connect模块传递store
connect: 负责连接React和Redux
(1)获取state: connect通过context获取Provider中的store,通过store.getState()获取整个store tree 上所有state
(2)包装原组件: 将state和action通过props的方式传入到原组件内部wrapWithConnect返回一个ReactComponent对象Connect,Connect重新render外部传入的原组件WrappedComponent,并把connect中传入的mapStateToProps, mapDispatchToProps与组件上原有的props合并后,通过属性的方式传给WrappedComponent
(3)监听store tree变化: connect缓存了store tree中state的状态,通过当前state状态和变更前state状态进行比较,从而确定是否调用this.setState()方法触发Connect及其子组件的重新渲染
redux-thunk优点:
体积小: redux-thunk的实现方式很简单,只有不到20行代码
使用简单: redux-thunk没有引入像redux-saga或者redux-observable额外的范式,上手简单
redux-thunk缺陷:
样板代码过多: 与redux本身一样,通常一个请求需要大量的代码,而且很多都是重复性质的
耦合严重: 异步操作与redux的action偶合在一起,不方便管理
功能孱弱: 有一些实际开发中常用的功能需要自己进行封装
(2)redux-saga
redux-saga优点:
异步解耦: 异步操作被被转移到单独 saga.js 中,不再是掺杂在 action.js 或 component.js 中
action摆脱thunk function: dispatch 的参数依然是一个纯粹的 action (FSA),而不是充满 “黑魔法” thunk function
异常处理: 受益于 generator function 的 saga 实现,代码异常/请求失败 都可以直接通过 try/catch 语法直接捕获处理
功能强大: redux-saga提供了大量的Saga 辅助函数和Effect 创建器供开发者使用,开发者无须封装或者简单封装即可使用
灵活: redux-saga可以将多个Saga可以串行/并行组合起来,形成一个非常实用的异步flow
易测试,提供了各种case的测试方案,包括mock task,分支覆盖等等
redux-saga缺陷:
额外的学习成本: redux-saga不仅在使用难以理解的 generator function,而且有数十个API,学习成本远超redux-thunk,最重要的是你的额外学习成本是只服务于这个库的,与redux-observable不同,redux-observable虽然也有额外学习成本但是背后是rxjs和一整套思想
体积庞大: 体积略大,代码近2000行,min版25KB左右
功能过剩: 实际上并发控制等功能很难用到,但是我们依然需要引入这些代码
ts支持不友好: yield无法返回TS类型
11、关于虚拟dom和diff算法
https://juejin.im/post/5cb66fdaf265da0384128445