1、说说你对react的理解?有哪些特性?
React,用于构建用户界面的 JavaScript 库,只提供了 UI 层面的解决方案 遵循组件设计模式、声明式编程范式和函数式编程概念,以使前端应用程序更高效 使用虚拟 DOM 来有效地操作 DOM,遵循从高阶组件到低阶组件的单向数据流 帮助我们将界面成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,构成整体页面
特性:JSX 语法 单向数据绑定 虚拟 DOM 声明式编程 Component
优势:高效灵活 声明式的设计,简单使用 组件式开发,提高代码复用率 单向响应的数据流会比双向绑定的更安全,速度更快
2、React组件之间如何通信?
react组件通信有几种方式:
- props传参
- pub-sub传参
- context发布者订阅者
- redux
props传参:
//父组件在子组件传递数据 import React, { Component } from 'react'; class Parents extends Component { render() { return ( <div> <Children state={'name':'list'} /> </div> ); } } //子组件在props中接受数据 import React, { Component } from 'react'; class Children extends Component { render() { let {name} = this.props return ( <div> {name} </div> ); } }
pub-sub传参:
需要预先下载pub-sub包
在需要传值的组件中,进行信息的发布(publish): publish方法的第一个参数(yyds)为订阅名,第二个参(message1)为想要传递的变量。 PubSub.publish (‘yyds’, ‘message1’) //通过事件触发方法发布信息‘message1’
context传参:
上下文(Context) 提供了一种通过组件树传递数据的方法,无需在每个级别手动传递 props 属性。 通过Provider(提供者) 后代和Consumer(使用者) 组件 进行通信
redux
redux是管理公共数据的一个存储,像vue脚手架中的vuex类似,所有的视图都可以操作在其中的数据。
起到一个传递数据以及减少缓存的效果
3、说说React生命周期有哪些不同的阶段?每个阶段对应的方法是?
这里主要讲述react16.4
之后的生命周期,可以分成三个阶段:
- 创建阶段
- 更新阶段
- 卸载阶段
创建阶段
创建阶段主要分成了以下几个生命周期方法:
- constructor
- getDerivedStateFromProps
- render
- componentDidMount
constructor
实例过程中自动调用的方法,在方法内部通过super关键字获取来自父组件的props
在该方法中,通常的操作为初始化state状态或者在this上挂载方法
getDerivedStateFromProps
该方法是新增的生命周期方法,是一个静态的方法,因此不能访问到组件的实例
执行时机:组件创建和更新阶段,不论是props变化还是state变化,也会调用
在每次render方法前调用,第一个参数为即将更新的props,第二个参数为上一个状态的state,可以比较props 和 state来加一些限制条件,防止无用的state更新
该方法需要返回一个新的对象作为新的state或者返回null表示state状态不需要更新
render
类组件必须实现的方法,用于渲染DOM结构,可以访问组件state与prop属性
注意: 不要在 render 里面 setState, 否则会触发死循环导致内存崩溃
componentDidMount
组件挂载到真实DOM节点后执行,其在render方法之后执行
此方法多用于执行一些数据获取,事件监听等操作
更新阶段
该阶段的函数主要为如下方法:
- getDerivedStateFromProps
- shouldComponentUpdate
- render
- getSnapshotBeforeUpdate
- componentDidUpdate
getDerivedStateFromProps
该方法介绍同上
shouldComponentUpdate
用于告知组件本身基于当前的props和state是否需要重新渲染组件,默认情况返回true
执行时机:到新的props或者state时都会调用,通过返回true或者false告知组件更新与否
一般情况,不建议在该周期方法中进行深层比较,会影响效率
同时也不能调用setState,否则会导致无限循环调用更新
render
介绍如上
getSnapshotBeforeUpdate
该周期函数在render后执行,执行之时DOM元素还没有被更新
该方法返回的一个Snapshot值,作为componentDidUpdate第三个参数传入
getSnapshotBeforeUpdate(prevProps, prevState) { console.log('#enter getSnapshotBeforeUpdate'); return 'foo'; } componentDidUpdate(prevProps, prevState, snapshot) { console.log('#enter componentDidUpdate snapshot = ', snapshot); }
此方法的目的在于获取组件更新前的一些信息,比如组件的滚动位置之类的,在组件更新后可以根据这些信息恢复一些UI视觉上的状态
componentDidUpdate
执行时机:组件更新结束后触发
在该方法中,可以根据前后的props和state的变化做相应的操作,如获取数据,修改DOM样式等
卸载阶段
componentWillUnmount
此方法用于组件卸载前,清理一些注册是监听事件,或者取消订阅的网络请求等
一旦一个组件实例被卸载,其不会被再次挂载,而只可能是被重新创建
参考文献
链接:
4、说说AMD、CMD、commonJS模块化规范的区别?
CommonJS
- 常用于:
服务器端
,node
,webpack
- 特点:
同步/运行时加载
,磁盘读取速度快
AMD
- 常用于:不常用,
CommonJs的浏览器端实现
- 特点:
异步加载
:因为面向浏览器端,为了不影响渲染肯定是异步加载依赖前置
:所有的依赖必须写在最初的依赖数组中,速度快,但是会浪费资源,预先加载了所有依赖不管你是否用到
CMD
- 常用于:不常用,
根据CommonJs和AMD实现,优化了加载方式
- 特点:
异步加载
按需加载/依赖就近
:用到了再引用依赖,方便了开发,缺点是速度和性能较差
5、说说你对webSocket的理解?
WebSocket,是一种网络传输协议,位于OSI
模型的应用层。可在单个TCP
连接上进行全双工通信,能更好的节省服务器资源和带宽并达到实时通迅
客户端和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输
优点
- 较少的控制开销:数据包头部协议较小,不同于http每次请求需要携带完整的头部
- 更强的实时性:相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少
- 保持创连接状态:创建通信后,可省略状态信息,不同于HTTP每次请求需要携带身份验证
- 更好的二进制支持:定义了二进制帧,更好处理二进制内容
- 支持扩展:用户可以扩展websocket协议、实现部分自定义的子协议
- 更好的压缩效果:Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率
应用场景
基于websocket
的事实通信的特点,其存在的应用场景大概有:
- 弹幕
- 媒体聊天
- 协同编辑
- 基于位置的应用
- 体育实况更新
- 股票基金报价实时更新
参考文献
链接: https://zh.wikipedia.org/wiki/WebSocket
链接: https://www.oschina.net/translate/9-killer-uses-for-websockets
链接: https://vue3js.cn/interview
6、React性能优化的手段有哪些?
1、使用纯组件;
2、使用 React.memo 进行组件记忆(React.memo 是一个高阶组件),对 于相同的输入,不重复执行;
3、如果是类组件,使用 shouldComponentUpdate(这是在重新渲染组件之前触发的其中一个生命周期事件)生命周期事件,可以利用此事件来决定何时需要重新渲染组件;
4、路由懒加载;
5、使用 React Fragments 避免额外标记;
6、组件优化,在子组件中判断子组件所依赖的数据是否发生变化,在进行渲染操作
7、常用的15个数组方法
1 push() unshift() 尾部头部添加 2 pop() shift() 尾部头部删除 3 reverse() 颠倒数组中的元素 4 splice() 添加或删除数组中的元素 5 foreach() 遍历数组 6 sort() 对于数组的元素进行排序 7 map() 将数组映射成为另一个数组 8 filter() 从数组中找出所有符合指定条件的元素 9 reduce() 将数组合成一个值 10 concat() 连接两个或多个字符串 11 slice() 数组复制 12. find() 返回通过测试(函数内判断)的数组的第一个元素的值 13. join() && toString() 把数组中的所有元素转换成一个符串 14. toLocaleString 把数组转换为本地字符串 15 indexOf() 查找指定的字符串值在字符串中首次出现(索引)位置。
8、受控组件和非受控组件的区别以及应用场景
受控组件简单来说就是受我们控制的组件
非受控组件就是不受我们控制的组件
两者区别 1、受控组件 受控组件依赖于状态 受控组件的修改会实时映射到状态值上,此时可以对输入的内容进行校验 受控组件只有继承React.Component才会有状态 受控组件必须要在表单上使用onChange事件来绑定对应的事件 2、非受控组件 非受控组件不受状态的控制 非受控组件获取数据就是相当于操作DOM
受控组件的应用场景主要就是react表单的应用,可以更好的进行数据的保存以及修改
9、组件优化
Component的2个问题
- 只要执行setState(),即使不改变状态数据, 组件也会重新render() ==> 效率低
- 只当前组件重新render(), 就会自动重新render子组件,纵使子组件没有用到父组件的任何数据 ==> 效率低
效率高的做法
只有当组件的state或props数据发生改变时才重新render()
原因
Component中的shouldComponentUpdate()总是返回true
解决
办法1: 重写shouldComponentUpdate()方法 比较新旧state或props数据, 如果有变化才返回true, 如果没有返回false 办法2: 使用PureComponent PureComponent重写了shouldComponentUpdate(), 只有state或props数据有变化才返回true 注意: 只是进行state和props数据的浅比较, 如果只是数据对象内部数据变了, 返回false 不要直接修改state数据, 而是要产生新数据 项目中一般使用PureComponent来优化
10、为什么react元素有一个$$type属性?
目的是为了防止 XSS 攻击。因为 Synbol 无法被序列化,所以 React 可以通过有没有 $$typeof 属性来断出当前的 element 对象是从数据库来的还是自己生成的。
如果没有 $$typeof 这个属性,react 会拒绝处理该元素。