【React】react面试题
React面试题
一、react特性
***React与Vue的区别
相同点:
1、react和vue都支持服务端渲染
2、都有虚拟DOM,组件化开发,通过props传参进行父子组件数据的传递
3、都是数据驱动视图
4、都有支持native的方案(react的react native,vue的weex)
5、都有状态管理(react有redux,vue有vuex)
不同点:
1、react严格上只能算是MVC的view层,vue则是MVVM模式
2、虚拟DOM不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树
而对于react而言,每当应用的状态被改变时,全部组件都会重新渲染,所以react中会需要shouldComponentUpdate这个生命周期函数方法来进行控制
3、组件写法不一样,react推荐的做法是JSX+inline style,也就是把HTML和CSS全都写进javaScript了
4、数据绑定:vue实现了数据的双向绑定,react数据流动是单向的
5、state对象在react应用中是不可变的,需要使用setState方法更新状态
在vue中,state对象不是必须的,数据有data属性在vue对象中管理
总结:React 的思路是 HTML in JavaScript 也可以说是 All in JavaScript,通过 JavaScript 来生成 HTML,所以设计了 JSX 语法,还有通过 JS 来操作 CSS。
而Vue 是把 HTML,CSS,JavaScript 组合到一起,用各自的处理方式,Vue 有单文件组件,可以把 HTML、CSS、JS 写到一个文件中,HTML 提供了模板引擎来处理。
1. Jsx的使用规范
jsx语法规则:
1.定义虚拟Dom不用写引号
例如:const vdom =
Hello, React
//不用引号2.标签种混入js表达式要有{}
3.样式类名指定使用className
4.内联样式,要用style={{key:value}}的形式去写
5.必须只有一个根标签
6.标签需要闭合
7.标签首字母:
1)若小写字母开头,则将标签改为html中同名元素
2)若大写字母开头,react则去渲染对应的组件,若组件没有定义,则报错
1.说说对 React 的理解?有哪些特性?
React,用于构建用户界面的 JavaScript 库,只提供了 UI 层面的解决方案
遵循组件设计模式、声明式编程范式和函数式编程概念,以使前端应用程序更高效
使用虚拟 DOM 来有效地操作 DOM,遵循从高阶组件到低阶组件的单向数据流
帮助我们将界面成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,构成整体页面
react 类组件使用一个名为 render() 的方法或者函数组件return,接收输入的数据并返回需要展示的内容
React 特性有很多,如:
JSX 语法
单向数据绑定
虚拟 DOM
声明式编程
Component
React 存在的优势:
高效灵活
声明式的设计,简单使用
组件式开发,提高代码复用率
单向响应的数据流会比双向绑定的更安全,速度更快
DOM
2.说说 Real DOM 和 Virtual DOM 的区别?优缺点?
两者的区别如下:
虚拟 DOM 不会进行排版与重绘操作,而真实 DOM 会频繁重排与重绘
虚拟DOM进行频繁修改,然后一次性比较并修改真实DOM中需要改的部分(注意!),最后并在真实DOM中进行排版与重绘,减少过多DOM节点排版与重绘损耗
真实DOM频繁排版与重绘的效率是相当低的
真实 DOM 的优势:
易用
缺点:
效率低,解析速度慢,内存占用量过高
性能差:频繁操作真实 DOM,易于导致重绘与回流
使用虚拟 DOM 的优势如下:
简单方便:如果使用手动操作真实 DOM 来完成页面,繁琐又容易出错,在大规模应用下维护起来也很困难
性能方面:使用 虚拟 DOM,能够有效避免真实 DOM 数频繁更新,减少多次引起重绘与回流,提高性能
跨平台:React 借助虚拟 DOM,带来了跨平台的能力,一套代码多端运行
缺点:
在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化
首次渲染大量 DOM 时,由于多了一层虚拟 DOM 的计算,速度比正常稍慢
说说React中的虚拟dom?在虚拟dom计算的时候diff和key之间有什么关系
虚拟dom:
原生的JS DOM操作非常消耗性能,而React把真实原生JS DOM转换成了JavaScript对象。这就是虚拟Dom(Virtual Dom)
每次数据更新后,重新计算虚拟Dom,并和上一次生成的虚拟dom进行对比,对发生变化的部分作批量更新。在此其中,React提供了componentShouldUpdate生命周期来让开发者手动控制减少数据变化后不必要的虚拟dom对比,提升性能和渲染效率。
diff和key之间关系:
当同一层级的某个节点添加了对于其他同级节点唯一的key属性,当它在当前层级的位置发生了变化后。react diff算法通过新旧节点比较后,如果发现了key值相同的新旧节点,就会执行移动操作(然后依然按原策略深入节点内部的差异对比更新),而不会执行原策略的删除旧节点,创建新节点的操作。这无疑大大提高了React性能和渲染效率
3.说说React Jsx转换成真实DOM过程?
jsx是JavaScript的一种语法扩展,它跟模板语言很接近,但是它充分具备JavaScript的能力
JSX就是用来声明React当中的元素,React使用JSX来描述用户界面
JSX语法糖允许前端开发者使用我们最熟悉的类HTML标签语法来创建虚拟DOM在降低学习成本
使用React.createElement或JSX编写React组件,实际上所有的 JSX
代码最后都会转换成React.createElement(…) ,Babel帮助我们完成了这个转换的过程。createElement函数对key和ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象
最终将虚拟Dom传入ReactDom.render函数中,将其转变为真实Dom
4.说说你第mvc和mvvm的理解
MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核心是提供对View 和 ViewModel 的双向数据绑定
MVC 即 Model-View-Controller 的缩写,就是 模型—视图—控制器
View
:用来把数据以某种方式呈现给用户
Model
:其实就是数据
Controller
:接收并处理来自用户的请求,并将 Model 返回给用户
MVVM和MVC的区别
MVVM实现了view(视图层)和model(数据层)之间的双向绑定,而MVC只实现了
model(数据层)和view(视图层)之间的单向绑定。即当model中的数据发生改变时
view(视图)会更新,但是view(视图)改变时model(数据)不会更新。MVVM中实现了将model(数据层)中的数据对象转成view(视图层)中的真实DOM的封
装,可以以最小的代价实现对dom的操作,而MVC中并没有做这样的处理。因此需要频
繁的操作DOM,降低了页面性能,用户体验差。
5.说说react中引入css的方式有哪几种?区别?
外联样式
定义css文件,在组件中通过import导入css样式,
import “App.css”
内联样式
React推崇的是内联的方式定义样式。这样做的目的就在于让你的组件更加的容易复用
定义一个style属性,属性中定义对应的css样式即可,比如style={{fontSize:‘15px’}}
外层花括号是语法,内层花括号是对象边界符,这种方式的反应样式,只作用于当前组件。
css in js解决方案
css in js 解决方案其实就是将css样式写在js文件里面的一种技术
下载aphrodite npm install --save aphrodite
从上面DevTools可以看出我们定义的样式存在于style标签内,而且选择器名字是一串随
机的哈希字符串,这样其实实现了局部CSS作用域的效果(scoping styles),各个组件
的样式不会发生冲突
radium使用
yarn add radium
对于处理变量,媒体查询,伪类等是不方便的。
使用Radium可以直接处理变量,媒体查询,伪类等,并且可以直接使用js中的数学,连接,正则表达式,条件,函数等。
styled-components使用
yarn add styled-components、
这种方式是将整个的CSS样式,和HTML节点整体合并成一个组件。引入这个组件的HTML和CSS都有了。
它的好处在于可以随时通过往组件上传入属性,来动态的改变样式。对于处理变量,媒体查询,伪类等较方便的。
css module
将css的文件名改为: App.module.css ,这样做会为你这个css文件下所有的id名或者class名
添加一个随机的后缀名。这样就可以防止和其它的文件冲突了
6.bind、call、apply 区别?如何实现一个bind?
三者都可以改变函数的
this
对象指向三者第一个参数都是
this
要指向的对象,如果没有这个参数或参数为undefined
或null
,则默认指向全局window
三者都可以传参,但是
apply
是数组,而call
是参数列表,且apply
和call
是一次性传入参数,而bind
可以分为多次传入bind返回的是一个改变了this指向的函数,便于稍后调用,不像call和apply会立即调用;bind和call很像,传入的也是参数列表,但是可以多次传入,不需要像call,一次传入
<button onClick={this.del.bind(this,index) }>
点击
箭头函数和普通函数的区别?箭头函数能当构造函数吗?*
普通函数存在着变量的提升,箭头函数没有
普通函数的this指向,谁调用指向谁,箭头函数是在哪定义就指向谁
普通函数可以当成构造函数,而箭头函数是不可以的
箭头函数没有arguments,要接受所有的参数用…rest
箭头函数不能作为构造函数的原因:
箭头函数没有prototype。因此不能使用箭头作为构造函数,也就不能通过new操作符来调用箭头函数。
7.对react中合成事件的理解
React 合成事件(SyntheticEvent)是 React 模拟原生 DOM 事件所有能力的一个事件对象,即浏览器原生事件的跨浏览器包装器。它根据 W3C 规范 来定义合成事件,兼容所有浏览器,拥有与浏览器原生事件相同的接口。
在 React 中,所有事件都是合成的,不是原生 DOM 事件,但可以通过 e.nativeEvent 属性获取 DOM 事件。
***合成事件和原生事件的区别
原生事件就是js的原生事件,如通过document.addEventListener来设置的监听事件;在react中即使有自己的一套事件机制(见下面合成事件),但有时候的业务场景我们仍然需要使用原生事件。比如我们封装一个Modal弹窗组件,需要在点击非弹窗区域时关掉弹窗,此时我们只能针对document进行原生点击事件监听。
8.对react中setState的理解
一个组件的显示形态可以由数据状态和外部参数所决定,而数据状态就是state, 当需要修改里面的值的状态需要通过调用setState来改变,从而达到更新组件内部数据的作用
setState第一个参数可以是一个对象,或者是一个函数,而第二个参数是一个回调函数,用于可以实时的获取到更新之后的数据
在使用setState更新数据的时候,setState的更新类型分成:同步更新,异步更新
在组件生命周期或React合成事件中,setState是异步
在setTimeout或者原生dom事件中,setState是同步
对同一个值进行多次 setState, setState 的批量更新策略会对其进行覆盖,取最后一次的执行结果
8.1. setState是同步还是异步
setState是同步还是异步,不是绝对的,根据不同情况,是不一样的,如下:
1、同步的情况
1)setState在setTimeout中是同步的。
2)setState在原生事件中是同步的,即通过dom绑定事件的方式实现。
2、异步的情况
1)setstate在合成事件中是异步的,这里说的异步实际上是react的批量更新,达到了提升性能的目的。
2)setstate在生命周期中是异步的
React怎么实现列表渲染
react中可以使用map方法渲染列表,return对应的页面结构即可, React 在渲染列表时,会要求开发者为每一个列表元素指定唯一的 key
,我们尽量不要使用index索引值作为key,如果对数据进行:逆序添加、逆序删除等破坏顺序操作:可能会引起页面更新错误问题。
React中key的作用是什么?
key是虚拟DOM对象的唯一标识,在更新显示时key起到极其重要的作用 ,简单的来说就是为了提高diff的同级比较的效率,避免原地复用带来的副作用
react采用的是自顶而下的更新策略,每次小的改动都会生成一个全新的的vdom,从而进行diff,如果不写key,就会发生本来应该更新却没有更新
9.react的事件机制
react自身实现了一套事件机制,包括事件的注册、事件的存储、事件的合成及执行等。
react 的所有事件并没有绑定到具体的dom节点上而是绑定在了document 上,然后由统一的事件处理程序来派发执行。
通过这种处理,减少了事件注册的次数,另外react还在事件合成过程中,对不同浏览器的事件进行了封装处理,抹平浏览器之间的事件差异。
React事件机制总结如下:
- React 上注册的事件最终会绑定在document这个 DOM 上,而不是 React 组件对应的 DOM(减少内存开销就是因为所有的事件都绑定在 document 上,其他节点没有绑定事件)
- React 自身实现了一套事件冒泡机制,所以这也就是为什么我们 event.stopPropagation()无效的原因。
- React 通过队列的形式,从触发的组件向父组件回溯,然后调用他们 JSX 中定义的 callback
- React 有一套自己的合成事件 SyntheticEvent
10.说说对React refs 的理解?应用场景?
创建ref的形式有三种:
- 传入字符串,使用时通过 this.refs.传入的字符串的格式获取对应的元素
- 传入对象,对象是通过 React.createRef() 方式创建出来,使用时获取到创建的对象中存在 current 属性就是对应的元素
- 传入hook,hook是通过 useRef() 方式创建,使用时通过生成hook对象的 current 属性就是对应的元素
在某些情况下,我们会通过使用refs来更新组件,但这种方式并不推荐,更多情况我们是通过props与state的方式进行去重新渲染子元素
但下面的场景使用refs非常有用:
- 对Dom元素的焦点控制、内容选择、控制
- 对Dom元素的内容设置及媒体播放
- 对Dom元素的操作和对组件实例的操作
- 集成第三方 DOM 库
****11.props和state的区别
props是指组件间传递的一种方式,props自然也可以传递state。由于React的数据流是自上而下的,所以是从父组件向子组件进行传递;另外组件内部的this.props属性是只读的不可修改!
state是组件内部的状态(数据),不能够直接修改,必须要通过setState来改变值的状态,从而达到更新组件内部数据的作用。
相同点:
两者都是 JavaScript 对象
两者都是用于保存信息
props 和 state 都能触发渲染更新
区别:
props 是外部传递给组件的,而 state 是在组件内被组件自己管理的,一般在 constructor 中初始化
props 在组件内部是不可修改的,但 state 在组件内部可以进行修改,通过setState修改
state 是多变的、可以修改
***13.受控组件和非受控组件
受控组件
由React控制的输入表单元素而改变其值的方式,称为受控组件。
比如,给表单元素input绑定一个onChange事件,当input状态发生变化时就会触发onChange事件,从而更新组件的state。
非受控组件
非受控组件指的是,表单数据由DOM本身处理。即不受setState()的控制,与传统的HTML表单输入相似,input输入值即显示最新值。
在非受控组件中,可以使用一个ref来从DOM获得表单值。
为什么react元素有一个$$type属性
这是一个有效的方法,因为JSON是不支持Symbol类型的。所以,即使用户提交了message信息,到最后服务端也不会保存typeof属性。如果没有这个属性,则拒绝处理该元素。
12.组件通信
父传子通信流程
在父组件中的子组件标签上绑定自定义属性,挂载传递的数据
子组件中props接受传递的数据,直接使用即可
子传父通信的流程
父组件中子组件标签上绑定一个属性,传递一个方法给子组件
子组件中通过props接受这个方法,直接调用,传递相应的参数即可
非父子组件通信*
发布订阅模式:基本原理:订阅者提供一个回调函数,保存到一个数组中;发布者调用数组中的回调函数,传递参数
context状态树传参:
在父组件中我们通过createContext() 创建一个空对象,在父组件的最外层我们使用Provider包裹数据,通过value绑定要传递的对象数据。
在嵌套的子组件中,我们有两种方式获取数据:
(1) 我们可以使用Customer标签,在标签中绑定一个箭头函数,函数的形参context就是value传递的数据
(2). class组件中我们可以定义static contextType=context对象,组件中直接使用this.context获取数据。
二、生命周期
*14.简述React的生命周期函数?
挂载阶段:
- constructor() 在 React 组件挂载之前,会调用它的构造函数。
- componentWillMount: 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。
- componentDidMount(): 在组件挂载后(插入 DOM 树中)立即调用
更新运行阶段:
* componentWillReceiveProps: 在接受父组件改变后的props需要重新渲染组件时用到的比较多,外部组件传递频繁的时候会导致效率比较低
* shouldComponentUpdate():用于控制组件重新渲染的生命周期,state发生变化,组件会进入重新渲染的流程,在这里return false可以阻止组件的更新
* render(): render() 方法是 class 组件中唯一必须实现的方法。
* *componentWillUpdate(): shouldComponentUpdate返回true以后,组件进入重新渲染完成之前进入这个函数。
* **componentDidUpdate(): 每次state改变并重新渲染页面后都会进入这个生命周期
卸载或销毁阶段
componentWillUnmount (): 在此处完成组件的卸载和数据的销毁。
15.React旧生命周期有哪些问题?
(1) componentWillMount ,在ssr中 这个方法将会被多次调用, 所以会重复触发多遍,同时在这里如果绑定事件,
将无法解绑,导致内存泄漏 , 变得不够安全高效逐步废弃。
(2) componentWillReceiveProps 外部组件多次频繁更新传入多次不同的 props,会导致不必要的异步请求
(3) componetWillupdate, 更新前记录 DOM 状态, 可能会做一些处理,与componentDidUpdate相隔时间如果过长, 会导致 状态不太信
*16.React新生命周期有哪些改变?
用 getDerivedStateFromProps替换了 compoentWillMount和compontWillReceiveProps生命周期函数
用getSnapshotBeforeUpdate函数替换componetWillUpdate方法,避免和CompoentDidUpdate函数中获取数据不一致的问题
React中getSnapshotBeforeUpdate如何使用,怎么理解
getSnapshotBeforeUpdate() 方法在最近一次渲染输出(提交到 DOM 节点)之前调用。
在 getSnapshotBeforeUpdate() 方法中,我们可以访问更新前的 props 和 state。
getSnapshotBeforeUpdate() 方法需要与 componentDidUpdate() 方法一起使用,否则会出现错误。
17.React在哪个生命周期请求接口,哪个清除定时器
对于异步请求,最好放在componentDidMount中去操作,对于同步的状态改变,可以放在componentWillMount中,一般用的比较少。
componentWillUnmount():在组件将要卸载时执行,一般在这里做善后或收尾工作,如:清除定时器,释放闭包函数变量
18.React性能优化是哪个生命周期,为什么?*
shouldComponentUpdate
减少不必要的重新渲染
三、路由
18.react的路由几种模式,是什么?实现原理?
两种路由模式:
一种是Hash路由模式,用的是HashRouter组件
一种是历史路由模式,用的是BrowserRouter组件绑定
实现原理:路由描述了 URL
与 UI
之间的映射关系,这种映射是单向的,即 URL 变化引起 UI 更新(无需刷新页面)
***区别:
1.兼容性不同
BrowserRouter 因为使用了H5的history API,不兼容IE9及以下
HashRouter 因为使用了url的哈希值兼容性更好
2.表现形式不同
HashRouter 地址栏带 #, BrowserRouter则不带 #
3.刷新对路由state参数的影响
BrowserRouter无影响,路由state保存在history对象中
HashRouter有影响,刷新后导致路由state参数丢失
react路由常用的组件有哪些?
HashRouter或BrowserRouter配置路由模式
Route 定义路由组件映射关系
Redirect 设置路由重定向
NavLink 或者Link 页面路由跳转
Switch 路由匹配,当path匹配到一个component之后,将不会再想下继续匹配,提高了程序效率
19.withRouter是干什么的?
不是所有组件都直接与路由相连(比如拆分的子组件)的,当这些组件需要路由参数时,使用withRouter就可以给此组件传入路由参数,将react-router的history、location、match三个对象传入props对象上,此时就可以使用this.props.history跳转页面了或者接受参数了
react路由跳转的方式有哪些?
声明式导航:
使用NavLink或者Link跳转, to属性后面跟字符串或者跟对象
编程式导航跳转:
props.history.push(url) 跳转页面可以返回上一页,保留历史记录
props.history.replace(url) 跳转页面,清空历史记录
props.history.go(num) 返回第几个页面
20.React路由传递参数的方式都有哪些,具体怎么传参?
可以使用动态路由传递参数:/user/:id
使用search传递参数:/user/?id=1
使用params传递 :/user/:id/:name
使用query/state传参:query/state:{id:1}
21.Link和NavLink的区别
Link和navlink都是用来跳转路由使用的,link中的to可以写路径,直接跳转到响应的路由文件,url会更新,组件会被重新渲染,但是页面不会重新加载…使用to链接组件时
Navlink:可以设置样式,会在匹配上当前的url的时候给已经渲染的元素添加参数.
react中路由懒加载的实现方式是什么
首先,我们需要在组件中引入lazy,Suspense这两个方法
然后我们需要通过Suspense组件 包裹着注册路由
通过lazy() api来动态import需要懒加载的组件
import的组件目前只支持export default的形式导出
Suspense来包裹懒加载的组件进行加载,可以设置fallback现实加载中效果
react路由嵌套如何配置?
配置父组件的路由地址,在父组件中配置子组件的路由映射关系
关闭父组件路由配置exact属性,避免精准匹配
父组件路由地址作为子组件路由地址的开始的一部分。比如父组件是/index 子组件应该是/index/子组件地址
四、redux
什么是Redux?
在react中每个组件的state是由自身进行管理,包括组件定义自身的state、组件之间的通信通过props传递、使用Context实现数据共享等,如果让每个组件都存储自身相关的状态,理论上来讲不会影响应用的运行,但在开发及后期我们将比较难以维护,所以我们可以把数据进行集中式的管理,redux就是一个实现上述集中管理的容器的工具,redux
并不是只应用在react
中,还与其他界面库一起使用,如Vue
Redux的三大原则
state数据必须是单一数据源
redux中的state数据必须 是只读的,只能通过dispatch调用actions修改
Reducer必须使用纯函数来执行修改
redux的执行原理
React的组件需要获取或者修改页面的数据,通过dispatch方法调用actions进入到Reducer函数中修改state的数据内容,state更新后,通知组件更新页面即可。
22.react-redux和redux的区别
redux和组件进行对接的时候是直接在组件中进行创建。react-redux是运用Provider将组件和store对接,使在Provider里的所有组件都能共享store里的数据,还要使用connect将组件和react连接。
获取state的方式不一样
redux获取state是直接通过store.getState()。
react-redux获取state是通过mapStateToProps函数,只要state数据变化就能获取最新数据
触发action的方式不一样。
redux是使用dispatch直接触发,来操作store的数据。
react-redux是使用mapDispathToProps函数然后在调用dispatch进行触发
23.Redux和Vuex区别***
Vuex改进了Redux中的Action和Reducer函数,以mutations变化函数取代Reducer,无需switch,只需在对应的mutation函数里改变state值即可
Vuex由于Vue自动重新渲染的特性,无需订阅重新渲染函数,只要生成新的State即可
Vuex数据流的顺序是:View调用store.commit提交对应的请求到Store中对应的mutation函数->store改变(vue检测到数据变化自动渲染)
通俗点理解就是,vuex弱化 dispatch,通过commit进行store状态的一次更变;取消了action概念,不必传入特定的action形式进行指定变更;弱化reducer,基于commit参数直接对数据进行转变,使得框架更加简易;
共同思想**
单—的数据源、变化可以预测
本质上: redux与vuex都是对mvm思想的服务,将数据从视图中抽离的一种方案。
24.redux如何进行异步请求?
首先,安装 Redux Thunk 中间件:npm install --save redux-thunk
然后,在创建 Redux store 的时候,使用 applyMiddleware 函数将 Redux Thunk 中间件传递给 createStore 函数
接下来,就可以在 action creator 中使用 Redux Thunk 中间件的函数 dispatch 和 getState 来发送异步请求了。
25.说说对Redux中间件的理解?常用的中间件有哪些?
Redux中,中间件就是放在就是在dispatch过程,在分发action进行拦截处理
当action发出之后,reducer立即算出state,整个过程是一个同步的操作
那么如果需要支持异步操作,或者支持错误处理、日志监控,这个过程就可以用上中间件,其本质上一个函数,对store.dispatch方法进行了改造,在发出 Action和执行 Reducer这两步之间,添加了其他功能
常用的redux中间件,如:
redux-thunk:用于异步操作
redux-logger:用于日志记录
26.在使用redux过程中,如何防止定义的action-type的常量重复
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。
Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象
Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
Hook
1.useMemo和usecallBack是如何做到性能提升的?
useMemo用来缓存值,保存每次渲染时,不会发生变化的值,减少计算。在一些开销较大且值不会变的场景下特别有用。
useCallback用来缓存函数。通常用于父子组件中,父组件传给子组件一个函数,父组件更新时,传递给子组件的函数也会被 重新创建。有时候传递给子组件的函数没必要重新创建,useCallback就可以缓存这个函数,不使这个函数重新被创建。
2.如何让useEffect支持async/await?
1、useEffect中的第一个回调参数返回的是一个clean-up函数,所以不能返回promise对象,更不能直接使用async/await,否则会报错;
2、可以在回调参数中使用async/await:
方法一:使用自执行函数
useEffect(()=>{ // 使用自执行函数 IIFE
(async function fn(){
await otherFn();
})()
},[])
方法二:在useEffect的回调参数内部定义一个async函数:
useEffect(()=>{
const fn=async ()=>{
// do something
await otherFn()
}
fn()
},[])
方法三:在useEffect外部定义async函数,在回调参数中去执行:
const fn=async ()=>{
// do something
await otherFn()
}
useEffect(()=>{
fn()
},[])
*3. React中常见的Hooks方法有哪些?
useState
useState()用于为函数组件引入状态。在useState()中,数组第一项为一个变量,指向状态的当前值。类似this.state,第二项是一个函数,用来更新状态,类似setState
useEffect
useEffect()接受两个参数,第一个参数是你要进行的异步操作,第二个参数是一个数组,用来给出Effect的依赖项。只要这个数组发生变化,useEffect()就会执行
useRef
相当于class组件中的createRef的作用,ref.current获取绑定的对象
useContext
接受context状态树传递的数据内容
useReducer
接受reducer函数和状态的初始值作为参数,返回一个数组,其中第一项为当前的状态值,第二项为发送action的dispatch函数
userMemo useCallback
useMemo 和 useCallback接收的参数都是一样,第一个参数为回调,第二个参数为要依赖的数据
共同作用:仅仅依赖数据发生变化, 才会调用,也就是起到缓存的作用。useCallback缓存函数,useMemo 缓存返回值。
***什么是高阶组件,有什么作用
高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。基本上,这是从React的组成性质派生的一种模式,我们称它们为“纯”组件, 因为它们可以接受任何动态提供的子组件,但它们不会修改或复制其输入组件的任何行为。
一个函数的参数是一个函数,或者 函数的返回值是一个函数,我们称这类函数是高阶函数。
什么是React高阶组件:一个组件的参数是组件,并且返回值是一个组件,我们称这类组件为高阶组件
withRouter() memo() react-redux中connect方法是高阶组件
React 中的高阶组件主要有两种形式:属性代理 和 反向继承。
属性代理: 是 一个函数接受一个 WrappedComponent 组件作为参数传入,并返回一个继承了 React.Component 组件的类,且在该类的 render() 方法中返回被传入的 WrappedComponent 组件反向继承:是 一个函数接受一个 WrappedComponent 组件作为参数传入,并返回一个继承了该传入 WrappedComponent 组件的类,且在该类的 render() 方法中返回 super.render() 方法。
五、课外
ES6都有哪些新增?
1、新增了let const关键字
let var const的区别
let 是代码块有效 var是全局有效
let 是不能重复声明的 var是可以多次声明
let不存在变量的提升 var存在变量的提升
const存储简单数据类型存储的是常量
2、新增的解构赋值
解构赋值针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
let [a,b]=[1,2]
let {user}={user:“xiaosi”}
3、新增了箭头函数
4、js的数据类型
5、es6新增了模块化
6、新增类class关键字
class关键字是es5构造函数+原型模式创建对象的语法糖。创建类的方式 class 类名{构造函数和方法} 通过extends关键字实现继承。
**说说你对SPA的理解
SPA是什么
单页Web应用(single page application,SPA),就是只有一个Web页面的应用,
是加载单个HTML页面,并在用户与应用程序交互时动态更新该页面的Web应用程序
单页面应用程序:
只有第一次会加载页面, 以后的每次请求, 仅仅是获取必要的数据.然后, 由页面中js解析获取的数据, 展示在页面中
传统多页面应用程序:
对于传统的多页面应用程序来说, 每次请求服务器返回的都是一个完整的页面
优势
减少了请求体积,加快页面响应速度,降低了对服务器的压力
更好的用户体验,让用户在web app感受native app的流畅
什么是防抖和节流
防抖和节流相同点:防抖和节流都是为了阻止操作高频触发,从而浪费性能。
防抖和节流区别:
防抖是触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。适用于可以多次触发但触发只生效最后一次的场景。
节流是高频事件触发,但在n秒内只会执行一次,如果n秒内触发多次函数,只有一次生效,节流会稀释函数的执行频率。
*React中如何使用防抖节流
https://blog.csdn.net/m0_46430338/article/details/121481542
**什么是重绘与回流
重绘:简单来说就是重新绘画,当给一个元素更换颜色、更换背景,虽然不会影响页面布局,但是颜色或背景变了,就会重新渲染页面,这就是重绘。
回流:当增加或删除dom节点,或者给元素修改宽高时,会改变页面布局,那么就会重新构造dom树然后再次进行渲染,这就是回流。
总结
重绘不会引起dom结构和页面布局的变化,只是样式的变化,有重绘不一定有回流。
回流则是会引起dom结构和页面布局的变化,有回流就一定有重绘。
不管怎么说都是会影响性能。
怎么进行优化或减少?
1.多个属性尽量使用简写,例如:boder可以代替boder-width、boder-color、boder-style
2.创建多个dom节点时,使用documentfragment创建
3.避免使用table布局
4.避免设置多层内联样式,避免节点层级过多
5.避免使用css表达式
6.将频繁重绘或回流的节点设置为图层,图层能够阻止该节点的渲染行为影响到别的节点(例:will-change\video\iframe等标签),浏览器会自动将该节点变为图层
React中的性能优化方案
减轻 state
在state中只存储和组件渲染相关的数据
不用做渲染的数据不要放在 state 中,直接挂载在 this 上即可。避免不必要的重新渲染
使用 shoundComponentUpdate 钩子函数手动更新组件。
使用纯组件 PureComponent 自动更新组件。使用方式和 Component 一致
使用纯组件
如果 React 组件为相同的状态和 props 渲染相同的输出,则可以将其视为纯组件。
对于像 this 的类组件来说,React 提供了 PureComponent 基类。扩展 React.PureComponent 类的类组件被视为纯组件。
它与普通组件是一样的,只是 PureComponents 负责 shouldComponentUpdate——它对状态和 props 数据进行浅层比较(shallow comparison)
如果先前的状态和 props 数据与下一个 props 或状态相同,则组件不会重新渲染。懒加载组件
说说你对事件循环的理解?
JavaScript是一门单线程的语言,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环
在JavaScript中,所有的任务都可以分为
同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等
谈谈你对BFC(css)的理解,列举几个实例?
简单的理解:BFC就是一个块级容器,它会隔离外部,让盒子里面的元素不影响外面的元素,也就是在搭建页面的时候,不影响外面的布局。
解决边距重叠问题、解决高度坍塌问题、解决相邻盒子浮动区域重叠问题等
https://blog.csdn.net/m0_45991266/article/details/126884334
对css3媒体查询的理解
媒体查询可以让我们根据设备显示器的特性(如视口宽度、屏幕比例、设备方向:横向或纵向)为其设定CSS样式,媒体查询由媒体类型和一个或多个检测媒体特性的条件表达式组成。媒体查询中可用于检测的媒体特性有 width 、 height 和 color (等)。使用媒体查询,可以在不改变页面内容的情况下,为特定的一些输出设备定制显示效果。
https://article.itxueyuan.com/2Dy5Z
js内存泄漏的几种情况
意外的全局变量、闭包引起的内存泄漏、DOM之外的引用、被遗漏的定时器和回调函数
怎样避免内存泄漏
1)减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收;
2)注意程序逻辑,避免“死循环”之类的 ;
3)避免创建过多的对象 原则:不用了的东西要及时归还。
https://blog.csdn.net/weixin_44786530/article/details/126617193
如何解决react页面不刷新
用reload 方法,该方法强迫浏览器刷新当前页面。语法:location.reload([bForceGet]) 参数: bForceGet, 可选参数, 默认为 false,从客户端缓存里取当前页。true, 则以 GET 方式,从服务端取最新的页面, 相当于客户端ctrl+ F5(“刷新”)
对Fiber架构的理解?解决了什么问题?
从框架角度上,他重写了react的核心代码
从编程角度上,Fiber是 React内部所定义的一种数据结构,它是 Fiber树结构 的节点单位,也就是新架构下的虚拟DOM
作用:fiber可以将一个任务分成多份,让他们在不同的时间内执行,实现了"增量渲 染",实现了可中断与恢复,最终实现更流畅的用户体验。
说说react diff的原理是什么?
React中的diff算法
为了优化diff算法,react中对普通的diff算法实行了三大策略,成功将时间复杂度降为O(n)
策略一:tree diff —— 层级对比
由于开发过程中极少出现DOM的跨层级移动,所以tree diff 忽略了DOM节点的跨层级移动。(react不建议开发人员跨层级移动DOM)
策略二:component diff —— 组件对比
同类型的两个组件,直接比较Virtual DOM树,不同类型的组件将会被判定作为脏组件(dirty component)处理,直接删除或创建新组件
策略三:element diff —— 节点对比
对于同一层级的一组子节点,通过分配唯一key值进行区分
https://blog.csdn.net/qq_42941302/article/details/107151189
如何使用css实现一个三角形?
1、使用 border 绘制三角形
2、使用 linear-gradient 绘制三角形
3、使用 conic-gradient 绘制三角形
4、transform: rotate 配合 overflow: hidden 绘制三角形
5、使用 clip-path 绘制三角形
6、利用字符绘制三角形
https://blog.csdn.net/SqlloveSyn/article/details/127607854
什么是强缓存和协商缓存?
强缓存是根据返回头中的 Expires 或者 Cache-Control两个字段来控制的,都是表示资源的缓存有效时间。
协商缓存是由服务器来确定缓存资源是否可用。 主要涉及到两对属性字段,都是成对出现的,即第一次请求的响应头带上某个字, Last-Modified 或者 Etag,则后续请求则会带上对应的请求字段 If-Modified-Since或者 If-None-Match,若响应头没有 Last-Modified 或者 Etag 字段,则请求头也不会有对应的字段。
浏览器缓存主要有一下优点:
减少重复数据请求,避免通过网络再次加载资源,节省流量。
降低服务器的压力,提升网站性能。
加快客户端加载网页的速度, 提升用户体验。
强缓存和协商缓存的区别:
如果浏览器命中强缓存,则不需要给服务器发请求;而协商缓存最终由服务器来决定是否使用缓存,即客户端与服务器之间存在一次通信。
在 chrome 中强缓存(虽然没有发出真实的 http 请求)的请求状态码返回是 200 (fromcache);而协商缓存如果命中走缓存的话,请求的状态码是 304 (not modified)。 不同浏览器的策略不同,在
FireFox中,from cache 状态码是 304.
说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?
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,简化了我们的使用
说说如何借助webpack来优化前端性能?
1、压缩代码
删除多余代码,注释,简化代码的写法等等方式。可以利用webpack的uglifyJsPlugin和ParallelUglifyPlugin来压缩js文件,利用cssnano来压缩css资源。
2、利用CDN加速:在构建过程中,将引用的静态资源修改为CDN上对应的路径。
3、Tree shaking:将代码中永远不会⾛到的⽚段删除掉。可以通过在启动webpack时追加参数 --optimize-minimize 来实现。
4、Code Splitting将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利⽤浏览器缓存。例如vue中的异步组件就是按需加载。
5、提取公共第三⽅库: 提取公共第三⽅库:来进⾏公共模块抽取,利⽤浏览器缓存可以⻓期缓存这些⽆需频繁变动的公共代码。
猜你喜欢
- 【React】React中Typecript的使用
- 目录一、创建React的TypeScript项目二、使用差别1、基本使用2、Props传值的差别3、State传参三、总结一、创建React的TypeScript项目见:如何在React项目中引入TypeScript?_duansamve的博客-CSDN博客二、使用差别1、基本使用其基本使用和javascript编写React项目时差不多这是一份.tsx文件代码:可以看到和之前的.jsx使用并无太大差别import React, { Component }
- 【AntDesignPro】Ant Design Pro学习记录—自定义菜单选中
- 页面增删改查,打开子页面时,要让父页面菜单选中,参考官网给出的方案菜单的高级用法 - Ant Design Pro 使用的V5版本,直接设置 parentKeys:['/product'] 即可export default [ { path: '/product', // 不展示菜单
- 【AntDesignPro】Ant Design Pro学习记录—DrawerForm的使用
- 在AntDesignPro中,ModalForm和DrawerForm是我最常用的两个表单组件,配置上,他们有很多相同的地方,也有差异的地方,相比较而言,DrawerForm我使用的更多。ModalForm<ModalForm title={标题} width={600} &n
- 【AntDesignPro】Ant Design Pro学习记录—搭建AntDesignPro脚手架
- 文章目录前言一、操作过程1.初始化2.完成后配置软连接3.继续执行4.进入应用5.安装依赖6.启动前言工作项目需要,使用了AntDesignPro开发,在此做一个学习研究记录。一、操作过程参考官网开始使用 - Ant Design Pro🏆 让中后台开发更简单 包含 table form 等多个组件。https://pro.ant.design/zh-CN/docs/getting-started在node.js npm yarn 环境配置好之后,按照官网操作运行1.初始化npm
- 【AntDesignPro】Ant Design Pro学习记录—ModalForm的使用(四)
- 一、 ModalForm自定义footer按钮参考官网,Modal弹框是可以自定义按钮的,原想着ModalForm的modalprops可以设置自定义footer,结果设置一直不生效,最终还是使用Modal嵌套了ProForm实现了功能,在此记录一下。ant design pro使用的V5版本。1、Modal自定义footer参考官网https://ant-design.antgroup.com/components/modal-cn?from=msidevs.net#components-mo
- 【React】使用React实现一个内容滑动组件
- 最近在做项目时遇到一个需求,需要让一个列表能够通过点击按钮进行滚动,每次都是一屏的距离,不足则结束。并且,这个列表项是在react-grid-layout中的某一个模块内。所以包裹这个列表的容器会随时发生变化。在完成这个组件后,通过这篇文章总结一下。UI/原型分析那么从上面的功能描述以及项目中的UI,我们可以分析得到这样一个假想图:我们需要实现一个容器来作为我们的可视区域,并且这个容器是可以伸缩的。列表内容如果超出容器的可视区域,那么就会被隐藏。需要左右都有按钮,来支持用户左右滑动内容来查看,每
- 【AntDesignPro】Ant Design Pro学习记录—ProTable的使用(一)
- 目录一、关于ProTable二、使用步骤1.新建页面2.修改接口3.接口调用4.数据显示和检索1)不同类型内容显示2)列表检索3)列表内容样式设置5.其它1)render的简单使用2)图片点击预览3)翻页总结前言因为项目需要,确定了Ant Design Pro框架来开发后台管理端,刚接触这套框架,而且配套的资料真的很少,只能基于官方demo和网上不完整的学习经验一次次尝试,终于有个像样的结果,记录一下研究学习的成果,也给需要的同学一些帮助。本次学习研究基于Ant Design Pro V5版本,
- 【React】前端框架 React 学习总结
- 目录一、React在HTML里的运用二、React框架的常用操作项目打包1、JSX基础语法规则2、state数据的使用3、生命周期4、数据的双向绑定与Ref5、PropTypes验证规则6、React里的插槽7、错误边界8、直接操作refs元素9、高阶组件的运用案例10、性能优化11、Hook生命周期钩子的使用12、React里的计算属性三、组件之间的传值1、父子组件之间传值2、子向父传值3、context实现跨层级通信context hook案例四、网络请求框架使用五、React路由的使用声明