12.使用 React hooks 怎么实现类里面的所有生命周期?
在 React 16.8 之前,函数组件也称为无状态组件
13.React事件和原生事件的执行顺序
为什么会有合成事件:
在传统的事件里,不同的浏览器需要兼容不同的写法,在合成事件中React提供统一的事件对象,抹平了浏览器的兼容性差异
React通过顶层监听的形式,通过事件委托的方式来统一管理所有的事件,可以在事件上区分事件优先级,优化用户体验。React在合成事件上对于16版本和17`版本的合成事件有很大不同
执行顺序总结:
16版本先执行原生事件,当冒泡到document时,统一执行合成事件,
17版本在原生事件执行前先执行合成事件捕获阶段,原生事件执行完毕执行冒泡阶段的合成事件,通过根节点来管理所有的事件,原生的阻止事件流会阻断合成事件的执行,合成事件阻止后也会影响到后续的原生执行
14.为什么react元素有一个$$type属性?
目的是为了防止 XSS 攻击。因为 Synbol 无法被序列化,所以 React 可以通过有没有 $$typeof 属性来断出当前的 element 对象是从数据库来的还是自己生成的。如果没有 $$typeof 这个属性,react 会拒绝处理该元素。
15.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。
16.如何让 useEffect 支持 async/await?
为什么不支持?
effect function 应该返回一个销毁函数(return返回的 cleanup 函数),如果 useEffect 第一个参数传入 async,返回值则变成了 Promise,会导致 react 在调用销毁函数的时候报错
useEffect如何支持async/await?
创建一个异步函数(async...await 的方式),然后执行该函数。
17. React 中可以做哪些性能优化?
使用纯组件 – 纯组件是指那些不依赖于外部状态或引用的组件
shouldComponentUpdate 优化
不要使用内联函数定义(如果我们使用内联函数,则每次调用“render”函数时都会创建一个新的函数实例)
function MyButton(props) { return ( <button onClick={() => console.log('Button clicked!')}> {props.label} </button> ); }
避免使用内联样式属性;
使用 immutable 不可变数据,在我们项目中使用引用类型时,为了避免对原始数据的影响,一般建议使用 shallowCopy 和 deepCopy 对数据进行处理,但是这样会造成 CPU 和 内存的浪费,所以推荐使用 immutable
优点:
降低了可变带来的复杂度
节省内存 ,immutable 使用结构共享尽量复用内存,没有被引用的对象会被垃圾回收
不会有并发问题(因为数据本身不可变)
拥抱函数编程
给子组件设置一个唯一的 key,因为在 diff 算法中,会用 key 作为唯一标识优化渲染
使用 React.memo 进行组件记忆(React.memo 是一个高阶组件),对 于相同的输入,不重复执行;
在函数组件中使用useCallback和useMemo来进行组件优化,依赖没有变化的话,不重复执行
路由懒加载
18.react 和 vue 有什么区别?
区别:
React 的思路是 HTML in JavaScript 通过 JavaScript 来生成 HTML,所以设计了 JSX 语法,还有通过 JS 来操作 CSS
Vue 是把 HTML,CSS,JavaScript 组合到一起,用各自的处理方式,Vue 有单文件组件,可以把 HTML、CSS、JS 写到一个文件中,HTML 提供了模板引擎来处理。
React 整体是函数式的思想,在 React 中是单向数据流,推崇结合 immutable 来实现数据不可变。
Vue 的思想是响应式的,也就是基于是数据可变的,通过对每一个属性建立 Watcher 来监听,当属性变化的时候,响应式的更新对应的虚拟 DOM。
React 的性能优化需要手动去做,而Vue的性能优化是自动的,但是Vue的响应式机制也有问题,就是当 state 特别多的时候,Watcher 会很多,会导致卡顿。
共同点:
React 与 Vue 存在很多共同点,例如他们都是 JavaScript 的 UI 框架,组件化开发,单项数据流,声明式编程,虚拟dom
优势:
React
灵活性和响应性:它提供最大的灵活性和响应能力。
丰富的JavaScript库:来自世界各地的贡献者正在努力添加更多功能。
可扩展性:由于其灵活的结构和可扩展性,React已被证明对大型应用程序更好。
不断发展: React得到了Facebook专业开发人员的支持,他们不断寻找改进方法。
Web或移动平台: React提供React Native平台,可通过相同的React组件模型为iOS和Android开发本机呈现的应用程序。
Vue
易于使用: Vue.js包含基于HTML的标准模板,可以更轻松地使用和修改现有应用程序。
更顺畅的集成:无论是单页应用程序还是复杂的Web界面,Vue.js都可以更平滑地集成更小的部件,而不会对整个系统产生任何影响。
更好的性能,更小的尺寸:它占用更少的空间,并且往往比其他框架提供更好的性能。
精心编写的文档:通过详细的文档提供简单的学习曲线,无需额外的知识; HTML和JavaScript将完成工作。
适应性:整体声音设计和架构使其成为一种流行的JavaScript框架。
它提供无障碍的迁移,简单有效的结构和可重用的模板。
总结:
Vue 的响应式机制也有问题,当 state 特别多的时候,Watcher 会很多,会导致卡顿,所以大型应用(状态特别多的)一般用 React,更加可控。
对于易用性来说,VUE 是更容易上手的,对于项目来说新人更容易接手。
19.React render方法的原理,在什么时候会触发?
原理:
在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件
render函数中的jsx语句会被编译成我们熟悉的js代码,在render过程中,react将新调用的render函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比较,更新dom树
触发机:
类组件调用 setState 修改状态
函数组件通过useState hook修改状态
一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行render方法,一旦父组件发生渲染,子组件也会渲染
20.React Hooks 在使用上有哪些限制?
不要在循环、条件或嵌套函数中调用 Hook;
在 React 的函数组件中调用 Hook。
21.React Hooks概述及常用的Hooks介绍?
Hooks是React 16.8版本引入的新特性,它为函数组件添加了一些类似于类组件中的状态和生命周期方法的功能
useState:用于在函数组件中添加状态管理功能。它返回一个由当前状态值和更新函数组成的数组,我们可以通过该数组来获取和更新状态的值。
useEffect:用于执行副作用操作,例如订阅事件、修改DOM等。它接受一个函数作为参数,该函数将在每次渲染完成后执行。
useContext:用于在组件间共享数据,它接受一个上下文对象作为参数,然后返回该上下文对象中提供的数据。
useReducer:用于对复杂状态进行管理。它接受一个reducer函数和初始状态作为参数,并返回一个由当前状态值和dispatch函数组成的数组。
useCallback:用于缓存函数以提高性能,类似于React.memo。
useMemo:用于缓存计算结果以提高性能,类似于记忆函数。
useRef:用于引用DOM节点或保存任意可变值,它返回一个可变的ref对象。
22.说说React生命周期中有哪些坑?如何避免?
getDerivedStateFromProps 容易编写反模式代码,使受控组件和非受控组件区分模糊
componentWillMount 在 React 中已被标记弃用,不推荐使用,主要的原因是因为新的异步架构会导致它被多次调用,所以网络请求以及事件绑定应该放到 componentDidMount 中
componentWillReceiveProps 同样也被标记弃用,被 getDerivedStateFromProps 所取代,主要原因是性能问题。
shouldComponentUpdate 通过返回 true 或者 false 来确定是否需要触发新的渲染。主要用于性能优化。
componentWillUpdate 同样是由于新的异步渲染机制,而被标记废弃,不推荐使用,原先的逻辑可结合 getSnapshotBeforeUpdate 与 componentDidUpdate 改造使用。
如果在 componentWillUnmount 函数中忘记解除事件绑定,取消定时器等清理操作,容易引发 bug。
如果没有添加错误边界处理,当渲染发生异常时,用户将会看到一个无法操作的白屏,所以一定要添加。
23.说说Real diff算法是怎么运作的?
Diff算法是虚拟DOM的一个必然结果,它是通过新旧DOM的对比,将在不更新页面的情况下,将需要内容局部更新
Diff算法遵循深度优先,同层比较的原则
react中diff算法主要遵循三个层级的策略:
tree层级:DOM节点的跨层级操作不做优化,只对相同层节点进行比较,只有删除创建操作,没有移动操作
conponent 层级:如果是同一类的组件,则会继续往下进行diff运算,如果不是则直接删除组件下的所有子节点,创建新的
element 层级:对于比较同一层级的节点们,每个节点在对应的层级用唯一的key作为标识,通过key知道节点的变化,移动旧集合节点位置,更新为新集合节点位置
24.调和阶段setState干了什么?
代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。
经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面;
在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染;
在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。
25.使用 redux 有哪些原则?
单一数据源:整个应用的全局 state 被存储在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。
State 是只读的:唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事情的普通对象。
使用纯函数来执行修改:为了描述 action 如何改变 state tree,你需要编写纯的 reducers。
26.说说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 整合多个中间件
27.对Redux中间件的理解?原理?常用中间件有哪些?
Redux中,中间件就是放在就是在dispatch过程,在分发action进行拦截处理, 其本质上一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能
实现原理:
applyMiddlewares的源码 中我们可以看到 ,所有中间件被放进了一个数组chain,然后嵌套执行,最后执行store.dispatch。可以看到,中间件内部(middlewareAPI)可以拿到getState和dispatch这两个方法
常用中间件:
redux-thunk:用于异步操作
redux-logger:用于日志记录
28.Redux 和 Vuex 有什么区别,它们有什么共同思想吗?
相同点:
state 共享数据
流程一致:定义全局state,触发,修改state
原理相似,通过全局注入store。
不同点:
实现原理:
Redux 使用的是不可变数据,而Vuex的数据是可变的。Redux每次都是用新的state替换旧的state,而Vuex是直接修改
Redux 在检测数据变化的时候,是通过 diff 的方式比较差异的,而Vuex其实和Vue的原理一样,是通过 getter/setter来比较的
表现层:
vuex定义了state、getter、mutation、action四个对象;redux定义了state、reducer、action。
vuex中state统一存放,方便理解;reduxstate依赖所有reducer的初始值
vuex有getter,目的是快捷得到state;redux没有这层,react-redux mapStateToProps参数做了这个工作。
vuex中mutation只是单纯赋值(很浅的一层);redux中reducer只是单纯设置新state(很浅的一层)。他俩作用类似,但书写方式不同
vuex中action有较为复杂的异步ajax请求;redux中action中可简单可复杂,简单就直接发送数据对象({type:xxx, your-data}),复杂需要调用异步ajax(依赖redux-thunk插件)。
vuex触发方式有两种commit同步和dispatch异步;redux同步和异步都使用dispatch
共同思想:
单一的数据源
变化可以预测
29.props和state相同点和不同点?
不同点:
props是只读的,只能由父组件传递给子组件,而不能在子组件中修改。而state是可变的,在组件内部可以通过setState方法来修改其值
相同点:
1.props和state都会触发渲染更新
2.props和state都是纯JS对象(用typeof来判断,结果都是object)
30.shouldComponentUpdate有什么作用?
shouldComponentUpdate () 可以理解为是否触发渲染的阀门,当状态发生改变时会走到该生命周期,shouldComponentUpdate接收两个参数props,state分别是更新前和更新后的状态,可以判断前后是否发生改变返回true和false,来决定是否往下执行
31.React的props.children使用map函数来遍历会收到异常显示,为什么?应该 如何遍历
原因:在react.js中props.children不一定是数组
当前组件没有子节点 undefined
有一个子节点 object
多个子节点 array
react资深提供了一个react.children.map()方法,可以安全遍历子节点对象。
32.谈谈你对immutable.js的理解?
Immutable.js采用了 持久化数据结构 ,保证每一个对象都是不可变的,任何添加、修改、删除等操作都会生成一个新的对象,且通过 结构共享 等方式大幅提高性能