2022 React 面试题(50道)

什么是同源?

如果两个页面(接口)的协议、域名、端口号都相同,我们认为他们具6511有相同的源

UmiJs和dva、roadhog是什么关系?

roadhog 是基于 webpack 的封装工具,目的是简化 webpack 的配置 umi 可以简单地理解为 roadhog + 路由,思路类似 next.js/nuxt.js,辅以一套插件机制,目的是通过框架的方式简化 React 开发 dva 目前是最纯粹的数据流,和 umi 和 roadhog 之间并没有相互的依赖关系,可以分开使用也可以一起使用。

redux异步请求用redux-thunk中间件

重绘和重排的区别:

  • 重绘:CSS 样式改变(例如:visibility,背景色的改变),使浏览器需要根据新的属性进行绘制。
  • 重排:我们对DOM的修改引发了DOM几何元素的变化,渲染树需要重新计算,重新生成布局,重新排列元素。

如果两个页面(接口)的协议、域名、端口号都相同,我们认为他们具有相同的源

UmiJs和dva、roadhog是什么关系?

roadhog 是基于 webpack 的封装工具,目的是简化 webpack 的配置 umi 可以简单地理解为 roadhog + 路由,思路类似 next.js/nuxt.js,辅以一套插件机制,目的是通过框架的方式简化 React 开发 dva 目前是最纯粹的数据流,和 umi 和 roadhog 之间并没有相互的依赖关系,可以分开使用也可以一起使用。

eventLoop(普通函数->宏任务->微任务)

队列 是一种 FIFO(First In, First Out) 的数据结构,它的特点就是 先进先出

是一种 LIFO(Last In, First Out)的数据结构,特点即 后进先出

宏任务一般是:包括整体代码script,setTimeout,setInterval、I/O、UI render。 微任务主要是:Promise、Object.observe、MutationObserver。

JavaScript数据类型

值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。

引用数据类型:对象(Object)、数组(Array)、函数(Function)。

react diff 原理(常考,大厂必考)

  • 把树形结构按照层级分解,只比较同级元素。
  • 给列表结构的每个单元添加唯一的 key 属性,方便比较。
  • React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)
  • 合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty.到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制.
  • 选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。

性能优化

1,减少http请求

2,将CSS文件放在头部,js文件放在底部

3,使用字体图标代替图片

4,压缩文件

5,图片懒加载

跨域问题

1,CORS:只要服务器端支持就行

2,Nginx代理跨域:配置一个代理服务器

3,Node中间件代理跨域

4,Websocket

5,JSONP:添加一个

输入URL之后发生了什么

1,浏览器通过DNS查找域名的IIP地址

2,浏览器与目标服务器简历TCP链接(三次握手)

3,浏览器通过http协议发送请求

4,服务器响应http请求

5,释放TCP链接

6,浏览器解析html代码

7,浏览器发送请求获取HTML中的资源

8,浏览器对页面进行渲染呈现给用户

如何使用react脚手架搭建一个项目

  • npx create-react-app app-name

调用 setState 之后发生了什么?

React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面,在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。

react中的组件传参

  • 父传子

#父传子将父组件中的属性传入子组件,子组件可以用props直接接收并使用。 复制代码

  • 子传父

#子传父是子组件调用父组件中传来的方法来改变父组件中的值。 复制代码

  • 非相关组件传参

#使用context上下文,通过使用context.Provider数据提供者来实现全局的数据共享。 复制代码

在react中class定义的组件生命周期钩子函数?

可以大致分为初始化阶段、运行中阶段和销毁阶段

初始化阶段


  • constructor( )
  • //设置组件的初始化状态
  • componentWillMount( )
  • //组件在挂载之前触发,这时可以开启定时器或者向服务器发送请求
  • render( )
  • //组件的渲染
  • componentDidMount( )
  • //组件已经渲染完毕,此时可以执行DOM的相关操作

运行中阶段

  • componentWillReceiveProps( )
  • //组件接收到新的属性时触发
  • shouldComponentUpdate( )
  • //当组件接收到新属性,或者组件的状态发生改变时触发。组件首次渲染时并不会触发

#此处可以对react进行优化处理,决定后续生命周期函数是否需要继续执行 shouldComponentUpdate(newProps, newState) {   if (newProps.number < 5) return true;   return false } //该钩子函数可以接收到两个参数,新的属性和状态,返回true/false来控制组件是否需要更新。 复制代码

  • componentWillUpdate( )
  • //组件更新之前触发
  • componentDidUpdate( )
  • //组件已经更新完毕,此时页面中产生了新的DOM元素,可以进行DOM操作

销毁阶段

  • componentWillUnMuont( )
  • //组件销毁之前触发,此时可以做一些清理操作,例如清除定时器,或者一些事件。

react中class定义的组件和function定义的组件的区别?

  • function定义的组件没有this指向的问题
  • class定义的组件有自己的局部状态(this.state)和自己的生命周期函数,function定义的组件是无状态组件,但是在16.8之后可以用hooks(useEffect)来模拟组件的局部状态和生命周期。
  • 官方建议使用function来定义组件,写法简单,并且便于理解。
  • 我目前一直在使用function来定义组件

react中hooks是如何模拟组件的生命周期的?

componentDidMount

function Example() { useEffect(() => console.log('mounted'), []); return null; } 复制代码

useEffect 拥有两个参数,第一个参数作为回调函数会在浏览器布局和绘制完成后调用,因此它不会阻碍浏览器的渲染进程。 第二个参数是一个数组

  • 当数组存在并有值时,如果数组中的任何值发生更改,则每次渲染后都会触发回调。
  • 当它不存在时,每次渲染后都会触发回调。
  • 当它是一个空列表时,回调只会被触发一次,类似于 componentDidMount。

componentDidUpdate

useEffect(() => console.log('count updated'),[count]); 复制代码

componentWillUnmount

useEffect(() => { return () => {   console.log('will unmount'); } }, []); 复制代码

  • 当在 useEffect 的回调函数中返回一个函数时,这个函数会在组件卸载前被调用。我们可以在这里面清除定时器或事件监听器。

react和vue的区别和共同点?

共同点:

  • 都使用虚拟dom。
  • 都提供了响应式和组件化的视图组件。
  • 都有全局状态管理的库。(vue-router、vuex、react-router、redux等等)

不同点:

  • 在性能方面,当组件的状态发生变化时,React的机制会触发整个组件树的重新渲染(shouldComponentUpdate()),Vue提供了优化的重新渲染,其中系统在渲染过程中跟踪依赖关系并相应地工作。重新渲染Vue是最显着的特征,使其成为全世界开发人员广泛接受的框架。
  • React react非常的灵活,并且它的库是非常丰富的,后盾是facebook,在react中数据是单向流动的,react在setState之后会重新走渲染的流程,如果shouldComponentUpdate返回的是true,就继续渲染,如果返回了false,就不会重新渲染,开发大型应用程序更好。
  • Vue vue性能更棒,占用空间更少,适合开发单页面应用程序,在vue中而Vue的思想是响应式的,也就是基于是数据可变的,通过对每一个属性建立Watcher来监听,当属性变化的时候,响应式的更新对应的虚拟dom,并且易于学习和上手,文档也比较友好。

react中的高阶组件有没有了解过?

  • 高阶组件就是一个没有副作用的纯函数。
  • 高阶组件是把一个组件当做参数,返回值为新组件的函数。
  • 高阶组件实际上就是高阶函数,如map、forEach
  • 常用的高阶组件:withRouter(路由中的),connect(reac-redux中的)

redux是什么?

  • redux是一个全局状态管理插件,用来操作数据的,它可以结合任何一个js库来使用(vue,安哥拉)等,react是一个针对视图层的library,一般结合react来使用。
  • redux是单向数据流,state用来存储数据,所有的数据改变都在reducer中进行,redux中还有一个action,用来组织数据。
  • 单向数据流:数据是单向流动的,view通过dispatch来派发一个action改变数据,数据改变之后,页面重新渲染。

redux分为三个部分:

  • state用来存储数据
  • reducer用来处理和改变数据,每一个reducer都是一个function,返回一个新的对象作为数据,目的是不进行原始数据的对比,使性能更高。
  • action用来组织数据,传递给reducer来进行数据的改变操作,每一个action都有一个属性叫type。表示数据以什么方式进行改变。

react中的错误边界?

  • React16.X中引入了错误边界(Error Boundaries)概念。
  • 它可以捕获它的子组件中产生的错误,类似于try-catch,只不过是以react组件的形式来实现的。
  • 有了错误边界,即使某个组件的结果有错误,整个React程序挂载也不会被挂掉。只有出错的那个组件会显示一个后备界面,而整个程序仍然完全正常运行。
  • 这里的componentDidCatch()函数使用方法和JavaScript中的catch {}代码块差不多,但只能用于组件。只有类组件才可以成为错误边界。
  • 在componentDidCatch()函数内部我们把hasError状态设置为true。然后在渲染方法中检查那个状态。如果出错状态是真,就渲染后备界面;如果是false就把想渲染的React组件界面当作子组件界面渲染出来。

尽管如此,以下错误Error Boundaries依旧无法捕获:

  • 事件错误
  • Error Boundaries本身的错误
  • 异步代码

react中react-router和react-router-dom的有什么区别?

api方面

  • React-router: 提供了路由的核心api。如Router、Route、Switch等,但没有提供有关dom操作进行路由跳转的api;
  • React-router-dom: 提供了BrowserRouter、Route、Link等api,可以通过dom操作触发事件控制路由。
  • Link组件,会渲染一个a标签;BrowserRouter和HashRouter组件,前者使用pushState和popState事件构建路由,后者使用 hash 和 hashchange 事件构建路由。

使用区别

  • react-router-dom在react-router的基础上扩展了可操作dom的api。 Swtich 和 Route 都是从react-router中导入了相应的组件并重新导出,没做什么特殊处理。
  • react-router-dom中package.json依赖中存在对react-router的依赖,故此,不需要额外安装react-router。

如何使用redux(使用流程)越详细越好?

  • 在脚手架中安装react-redux
  • 使用createStore去创建一个全局的store,用来保存所有的state,createStore接收一个reducer作为参数,你可以使用combineReducers传入多个reducer。
  • 在reducer中,接收两个参数,第一个参数表示数据的初始状态,第二个参数表示action,并且reducer会返回一个新的对象作为数据,这样的话可以不进行原始对象的比较,性能会提高。
  • 想要改变数据的话,就是view通过dispatch去派发一个action去执行相应的reducer,并且在store中进行更新,store改变的话,view就会重新渲染。
  • 我们可能要使用react-redux中的connect和Provider方法 去关联我们的数据。Provider通过context上下文向子组件提供store,connect把redux中的数据和组件中的props做关联,这里用到的方法是mapStateToProps把store中的数据去映射到组件的props中,这样在组件中就可以通过props去访问到redux中的数据。
  • 如果需要发送异步请求的话,还需要react-thunk插件,需要在creaceStore中做一个配置。

react中的key值有什么作用?

  • key属性的使用,则涉及到diff算法中同级节点的对比策略,当我们指定key值时,key值会作为当前组件的id,diff算法会根据这个id来进行匹配。如果遍历新的dom结构时,发现组件的id在旧的dom结构中存在,那么react会认为当前组件只是位置发生了变化,因此不会将旧的组件销毁重新创建,只会改变当前组件的位置,然后再检查组件的属性有没有发生变化,然后选择保留或修改当前组件的属性。
  • 用key是为了区分在前后两次渲染中元素的对应关系,防止发生不必要的更新操作。如果我们用index来标识key,数组在执行插入、排序等操作之后,原先的index并不再对应到原先的值,那么这个key就失去了本身的意义,并且会带来一些其他的问题。

react hooks解决什么问题?

  • react hooks 解决了函数定义的组件没有生命周期和局部状态的问题,使用hooks可以模拟类定义组件的生命周期。

两种路由模式的区别?hash和history?

  • hash路由 hash模式是通过改变锚点(#)来更新页面URL,并不会触发页面重新加载,我们可以通过window.onhashchange监听到hash的改变,从而处理路由hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
  • history路由 history模式是通过调用window.history对象上go、back、forward去操作浏览器的历史记录栈来实现页面的无刷新跳转。

解释useEffect的第二个参数传不同值的区别;

useEffect 拥有两个参数,第一个参数作为回调函数会在浏览器布局和绘制完成后调用,因此它不会阻碍浏览器的渲染进程。第二个参数是一个数组:

  • 当数组存在并有值时,如果数组中的任何值发生更改,则每次渲染后都会触发回调。
  • 当它不存在时,每次渲染后都会触发回调。
  • 当它是一个空列表时,回调只会被触发一次,类似于componentDidMount。

什么是纯函数?

  • 返回一个新值,并且没有任何副作用。

reducer是纯函数吗?为什么?

  • reducer必须是一个纯函数,Redux只通过比较新旧两个对象的存储位置来比较新旧两个对象是否相同。如果你在reducer内部直接修改旧的state对象的属性值,那么新的state和旧的state将都指向同一个对象。因此Redux认为没有任何改变,返回的state将为旧的state。

你认为vue和react有什么区别?

  • vue是单文件组件,组件内部是使用高度封装的模板(template)语法,数据是双向绑定。
  • react是jsx语法,并且数据是单向流动的。
  • vue是一个完整的框架,react主要是针对视图层的一个library
  • vue和react都是用了虚拟的dom。

可控组件和非可控组件是什么?

  • 主要是表单的value是否受state控制
  • 需要自行监听onChange,更新state

介绍一下hooks?

  • useState 定义局部状态
  • useEffect 模拟生命周期
  • useRefs 使用ref获取dom
  • useContext context上下文
  • useParams 获取url中的params
  • useLocation 获取url中的location对象
  • useMemo 做性能优化
  • useCallback

redux性能优化的最佳实践

  • pureComponent中自带shouldComponentUpdate这个生命周期。
  • 如果是普通component,当组件接收到新的props时,render都会重新渲染,如果是pureComponent,那么当传入新的props时会跟旧的props进行一个浅比较,如果没有变化,那么render函数不会重新渲染。
  • 一般会和immutable.js这个库结合使用,会将性能优化做到极致。

虚拟dom是什么?为什么虚拟dom会提升react的性能?

  • 虚拟dom实际上是一个js对象。
  • 真实dom进行比对的时候,非常复杂,真实dom树上会有方法,有属性,有事件,会非常消耗性能。通过将真实dom对象转化成js中的对象,就不具有真实dom中的特性,单纯比较js对象性能就会比较快。

diff算法是什么?

  • diff算法中如果key值相同就直接复用,不用重复地创建dom了。

webpack中,是借助loader完成JSX的转化?还是babel?

  • 因为react的代码是没办法直接在浏览器中运行的,是借助脚手架将代码转化为ES5,才得以在浏览器中运行,(在vue中是借助webpack中的vue-loader转化)react是借助babel中的preset-react来转化的。

setState是异步的,你在什么时候遇到过坑?

  • setState是异步的,导致在setState之后获取refs会是上一次的值。
  • 放在setState中的第二个回调函数中就可以解决这个问题。

ref的作用是什么,你在什么业务场景下使用过refs?

  • ref用来获取dom元素
  • 比如当一个图片加载完毕的时候,我想获取这个图片的宽和高,就要用到refs,比如放大镜。

redux中间件的原理是什么?

  • 中间件实际是对dispatch的改装
  • 中间件指的是action和store之间对dispatch的改装
  • 派发action的时候,先走中间件,再去store中
  • 从action (中间件)-> store -> reducer -> store

你会把数据统一放到redux中管理,还是把共享数据放在redux中管理?

  • 所有的数据都应该放在redux中去管理。
  • 当一个组件中既有state又有props和redux存储来存储数据。一个组件二三百行,查错不知道去哪儿查,这样不便于维护。
  • 当业务逻辑需要拓展的时候,state中存储数据,当别的组件需要你这个数据的时候,会很麻烦,redux更方便。
  • 不必担心redux消耗内存,redux内存5个G(chrome浏览器)

componentWillReceiveProps的调用时机?

  • componentWillReceiveProps这个生命周期在16.3之后已经被废弃,在组件接受到一个新的props时被调用,当组件初始化render的时候不会被调用。

setState是同步的还是异步的?

  • 看具体情况:
  • 首先如果直接在setState后面获取state的值是获取不到的,在原生环境中是异步的。
  • 在异步请求(ajax中)或者setInterval,setTimeout,setState就是同步更新的。

执行两次setState的时候会render几次?会不会立即触发?

  • 只执行一次,不会立即触发,因为react中有批处理机制,React会把setState的调用合并为一个来执行,也就是说,当执行setState的时候,state中的数据并不会马上更新,会按照先进先出,按顺序进行执行,但是在 Ajax、setTimeout 等异步方法中,每 setState 一次,就会 re-render 一次。

为什么直接修改this.state无效

setState本质是通过一个队列机制实现state更新的。 执行setState时,会将需要更新的state放入状态队列,而不会立刻更新state,队列机制可以批量更新state。 如果不通过setState而直接修改this.state,那么这个state不会放入状态队列中,下次调用setState时对状态队列进行合并时,会忽略之前直接被修改的state,这样我们就无法合并了,而且实际也没有把你想要的state更新上去。

react事件和dom事件区别

  • 所有事件挂载到 document上;event不是原生对象,是syntheticEvent合成的事件对象;dispatchEvent

state 和 props 区别是啥?

  • state 是组件自己管理数据,控制自己的状态,可变;
  • props 是外部传入的数据参数,不可变;
  • 没有state的叫做无状态组件,有state的叫做有状态组件;
  • 多用 props,少用 state,也就是多写无状态组件。

请简述TCP\UDP的区别

  • TCP面向连接,UDP面向非连接即发送数据前不需要建立链接
  • TCP提供可靠的服务(数据传输),UDP无法保证
  • TCP面向字节流,UDP面向报文
  • TCP数据传输慢,UDP数据传输快

React.memo()和React.PureComponent组件异同:

  • 异:React.memo()是函数组件,React.PureComponent是类组件。
  • 同:都是对接收的props参数进行浅比较,解决组件在运行时的效率问题,优化组件的重渲染行为。
  • useMemo()是定义一段函数逻辑是否重复执行。
  • 若第二个参数为空数组,则只会在渲染组件时执行一次,传入的属性值的更新也不会有作用。 所以useMemo()的第二个参数,数组中需要传入依赖的参数。

如何避免Ajax数据的重新获取

  • 使用react-redux来进行全局状态的管理
  • 判断redux中有没有之前的数据,如果有就直接复用,不需要再次发送请求。

组件是什么,类是什么,类被编译成什么?

  • 组件是页面的一部分,是一个功能的集合。
  • 类实际上是构造函数。
  • 类就是被编译成了构造函数。

reselect是什么

  • 类似于vue中的computed计算属性
  • 派生数据
  • 存在值的缓存,为了做性能优化

React-router的基本原理,hashHistory,和BrowserHistory。

  • 使用HashHistory不需要后端做配合。
  • BrowserHistory需要后端的配置,假如后端不太行,建议不用这个。

什么情况下使用异步组件

  • Reloadable库
  • 当主文件体积过大的时候,使用异步组件
  • 就是一种路由懒加载(按需加载)

在react中如何防范XSS攻击

  • 慎用:dangerousSetInnerHTML={{__html:alert(1)}}

getDerivedStateFromProps?

  • 是为了替代16.3中被废弃的ComponentShouldUpdate

数据结构算法

// 4.排序 let num=[0,0,33,24,5,33,7,2,8,1] datas.sort((a,b)=>{ return a-b }) // 5,for in--对象 let obj={name:'张三',age:19} for(let m in obj){ console.log(obj[m]);//张三,19; console.log(m);//name,age; } // 6,for of--数组 let arr=[1,2,3,4,5]; for(let i of arr){ console.log('for-of',i);//1,2,3,4,5 } // 7,出现最多的console.log('res---->',res); //2,tree树形转换成扁平数组结构 function falten(data){ return data.reduce((pre,cur)=>{ let {id,name,pid,children=[]}=cur; return pre.concat([{id,name,pid}],falten(children)) },[]) } let flat=falten(res) console.log('flat----->',flat); //3,去重 let num=[0,0,33,24,5,33,7,2,8,1] function chong(data){ //<1> return Array.from(new Set(data)) // <2>, let datas=[] data.forEach((item,index)=>{ if(datas.indexOf(data[index])===-1){ datas.push(item) } }) // 4.排序 let num=[0,0,33,24,5,33,7,2,8,1] datas.sort((a,b)=>{ return a-b }) // 5,for in--对象 let obj={name:'张三',age:19} for(let m in obj){ console.log(obj[m]);//张三,19; console.log(m);//name,age; } // 6,for of--数组 let arr=[1,2,3,4,5]; for(let i of arr){ console.log('for-of',i);//1,2,3,4,5 }

作者:前端小王子M
链接:https://juejin.cn/post/7091919870253760520
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 6
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值