• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

react的理解

武飞扬头像
Sink_web
帮助1

1.说说你对react的理解?有哪些特性?

React是一个简单的javascript UI库,用于构建高效、快速的用户界面。

它是一个轻量级库,因此很受欢迎。它遵循组件设计模式、声明式编程范式和函数式编程概念,以使前端应用程序更高效。

它使用虚拟DOM来有效地操作DOM。

它遵循从高阶组件到低阶组件的单向数据流。

React特性有很多,如:

  • JSX语法

  • 单向数据绑定

  • 虚拟DOM

  • 声明式编程

  • Component

    优势

  • 通过上面的初步了解,可以感受到React存在的优势:

  • 高效灵活

  • 声明式的设计,简单使用

  • 组件式开发,提高代码复用率

  • 单向响应的数据流会比双向绑定的更安全,速度更快

2.说说Real diff算法是怎么运作的?

Vue一致,React通过引入Virtual DOM的概念,极大地避免无效的Dom操作,使我们的页面的构建效率提到了极大的提升

diff算法就是更高效地通过对比新旧Virtual DOM来找出真正的Dom变化之处

原理

reactdiff算法主要遵循三个层级的策略:

  • tree层级

  • conponent 层级

  • element 层级

tree层级

DOM节点跨层级的操作不做优化,只会对相同层级的节点进行比较

只有删除、创建操作,没有移动操作

conponent层级

如果是同一个类的组件,则会继续往下diff运算,如果不是一个类的组件,那么直接删除这个组件下的所有子节点,创建新的

element层级

对于比较同一层级的节点们,每个节点在对应的层级用唯一的key作为标识

提供了 3 种节点操作,分别为 INSERT_MARKUP(插入)、MOVE_EXISTING (移动)和 REMOVE_NODE (删除)

3.说说React生命周期有哪些不同的阶段?每个阶段对应的方法是?

生命周期(Life Cycle)的概念应用很广泛,特别是在经济、环境、技术、社会等诸多领域经常出现,其基本涵义可以通俗地理解为“从摇篮到坟墓”(Cradle-to-Grave)的整个过程

React整个组件生命周期包括从创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程

这里主要讲述react16.4之后的生命周期,可以分成三个阶段:

  • 创建阶段

  • 更新阶段

  • 卸载阶段

创建阶段

  • constructor

  • getDerivedStateFromProps

  • render

  • componentDidMount

constructor

实例过程中自动调用的方法,在方法内部通过super关键字获取来自父组件的props

在该方法中,通常的操作为初始化state状态或者在this上挂载方法

getDerivedStateFromProps

该方法是新增的生命周期方法,是一个静态的方法,因此不能访问到组件的实例

执行时机:组件创建和更新阶段,不论是props变化还是state变化,也会调用

在每次render方法前调用,第一个参数为即将更新的props,第二个参数为上一个状态的state,可以比较propsstate来加一些限制条件,防止无用的state更新

该方法需要返回一个新的对象作为新的state或者返回null表示state状态不需要更新

render

类组件必须实现的方法,用于渲染DOM结构,可以访问组件stateprop属性

注意: 不要在 render 里面 setState, 否则会触发死循环导致内存崩溃

componentDidMount

组件挂载到真实DOM节点后执行,其在render方法之后执行

此方法多用于执行一些数据获取,事件监听等操作

更新阶段

  • getDerivedStateFromProps

  • shouldComponentUpdate

  • render

  • getSnapshotBeforeUpdate

  • componentDidUpdate

shouldComponentUpdate

用于告知组件本身基于当前的propsstate是否需要重新渲染组件,默认情况返回true

执行时机:到新的props或者state时都会调用,通过返回true或者false告知组件更新与否

一般情况,不建议在该周期方法中进行深层比较,会影响效率

同时也不能调用setState,否则会导致无限循环调用更新

getSnapshotBeforeUpdate

该周期函数在render后执行,执行之时DOM元素还没有被更新

该方法返回的一个Snapshot值,作为componentDidUpdate第三个参数传入

componentDidUpdate

执行时机:组件更新结束后触发

在该方法中,可以根据前后的propsstate的变化做相应的操作,如获取数据,修改DOM样式等

卸载阶段

componentWillUnmount

此方法用于组件卸载前,清理一些注册是监听事件,或者取消订阅的网络请求等

一旦一个组件实例被卸载,其不会被再次挂载,而只可能是被重新创建

4.说说你对React中虚拟dom的理解?

实际上它只是一层对真实DOM的抽象,以JavaScript 对象 (VNode 节点) 作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实环境上

创建虚拟DOM就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟DOM对象的节点与真实DOM的属性一个一个地照应

虚拟DOM的实现原理

React虚拟DOM的实现原理,通过JS模拟网页文档节点,生成JS对象树(虚拟DOM),然后再进一步生成真实的DOM树,再绘制到屏幕。如果后面有内容发生改变,React会重新生成一棵全新的虚拟DOM树,再与前面的虚拟DOM树进行比对diff,把差异的部分打包成patch,再应用到真实DOM,然后渲染到屏幕浏览器。

5.说说你对react hook的理解?

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性

至于为什么引入hook

  • 难以重用和共享组件中的与状态相关的逻辑

  • 逻辑复杂的组件难以开发与维护,当我们的组件需要处理多个互不相关的 local state 时,每个生命周期函数中可能会包含着各种互不相关的逻辑在里面

  • 类组件中的this增加学习成本,类组件在基于现有工具的优化上存在些许问题

  • 由于业务变动,函数组件不得不改为类组件等等

Hooks让我们的函数组件拥有了类组件的特性,例如组件内的状态、生命周期

通过对上面的初步认识,可以看到hooks能够更容易解决状态相关的重用的问题:

  • 每调用useHook一次都会生成一份独立的状态

  • 通过自定义hook能够更好的封装我们的功能

编写hooks为函数式编程,每个功能都包裹在函数中,整体风格更清爽,更优雅

hooks`的出现,使函数组件的功能得到了扩充,拥有了类组件相似的功能,在我们日常使用中,使用`hooks`能够解决大多数问题,并且还拥有代码复用机制,因此优先考虑`hooks

6.React组件之间如何通信?

父子组件通信

父组件要把数据传递给子组件,就通过props传过去。子组件可以通过this.props方法来获得传递过来的数据,这种是最基本,很常见的,几乎每个写 react 的人都会用到吧。

然而 react 的数据流向是单向的,如果子组件要传递数据给父组件就要一些技巧,不过这种情况也很常见。

就是首先父组件传递一个方法名给子组件,这个方法必须先在父组件定义好,比如叫父组件叫ElementGroup,子组件叫Element,这时候可以在渲染子组件的时候,传递一个方法,叫deleteElement

兄弟间

兄弟间的组件,我们有一个共同的特点,就是父级组件,所以它们的数据传递主要是靠父级组件作为中间桥梁。

7.说说你对受控组件和非受控组件的理解?应用场景?

受控组件,简单来讲,就是受我们控制的组件,组件的状态全程响应外部数据

我们在输入框输入内容的时候,会发现输入的内容并无法显示出来,也就是input标签是一个可读的状态

如果想要解除被控制,可以为input标签设置onChange事件,输入的时候触发事件函数,在函数内部实现state的更新,从而导致input框的内容页发现改变

受控组件我们一般需要初始状态和一个状态更新事件函数

非受控组件

非受控组件,简单来讲,就是不受我们控制的组件

一般情况是在初始化的时候接受外部数据,然后自己在内部存储其自身状态

大部分时候推荐使用受控组件来实现表单,因为在受控组件中,表单数据由React组件负责处理

如果选择非受控组件的话,控制能力较弱,表单数据就由DOM本身处理,但更加方便快捷,代码量少

针对两者的区别

8.说说Connect组件的原理是什么?

作用:连接React组件与Redux Store

在使用介绍connect之前, 先简单介绍一下什么是高阶组件

高阶组件就是一个函数,传给它一个组件,它返回一个新的组件。

connect有四个参数, 但是后两个参数用到的很少

connect 的第一个参数是 mapStateToProps

这个函数允许我们将 store 中的数据作为 props 绑定到组件上,实现主要原理, 就是将需要绑定的props作为一个函数传过来, 在connect中传给mapStateToProps一个真实的store的数据

connect 的第二个参数是 mapDispatchToProps

由于更改数据必须要触发action, 因此在这里的主要功能是将 action 作为props 绑定到 组件上, 主要是将actionprops一起传到组件里.

9.说说react 中jsx语法糖的本质

Jsx是语法糖,实质是js函数,需要babel来解析,核心函数是React.createElement(tag,{attrbuties},children),参数tag是标签名可以是html标签和组件名,attrbuties参数是标签的属性,children参数是tag的子元素。用来创建一个vnode,最后渲染到页面上

10.说说你对redux中间件的理解?常用的中间件有哪些?实现原理?

中间件(Middleware)是介于应用系统和系统软件之间的一类软件,它使用系统软件所提供的基础服务(功能),衔接网络上应用系统的各个部分或不同的应用,能够达到资源共享、功能共享的目的

类似于插件,可以在不影响原本功能、并且不改动原本代码的基础上,对其功能进行增强。在Redux中,中间件主要用于增强dispatch函数。

Redux中,中间件就是放在就是在dispatch过程,在分发action进行拦截处理,

常用的中间件

有很多优秀的redux中间件,如:

  • redux-thunk:用于异步操作

  • redux-logger:用于日志记录

上述的中间件都需要通过applyMiddlewares进行注册,作用是将所有的中间件组成一个数组,依次执行

然后作为第二个参数传入到createStore

实现原理

中间件本身是一个函数,该函数接收一个store参数,表示创建的仓库,该仓库并非一个完整的仓库对象,仅包含getState,dispatch。该函数运行的时间,是在仓库创建之后运行。

  • 由于创建仓库后需要自动运行设置的中间件函数,因此,需要在创建仓库时,告诉仓库有哪些中间件

  • 需要调用applyMiddleware函数,将函数的返回结果作为createStore的第二或第三个参数。

中间件函数必须返回一个dispatch创建函数

11.说说AMD、CMD、commonJS模块化规范的区别?

这三个规范都是为Js模块化加载而生的,使模块能够按需加载,使系统同庞杂的代码得到组织和管理。模块化的管理代码使多人开发得到了更好的合作

CommonJS

  • 常用于:服务器端nodewebpack

  • 特点:同步/运行时加载磁盘读取速度快

  • 语法:

// 1. 导出:通过module.exports或exports来暴露模块  
module.exports = {  
  attr1,  
  attr2  
}  
exports.attr = xx  

注意 不可以exports = xxx,这样写会无效,因为更改了exports的地址 而 exports 是 module.exports 的引用指向的是同一个内存,模块最后导出的是module.exports

// 2. 引用:require('x')  
const xx = require('xx') // 整体重命名  
const { attr } = require('xx') // 解构某一个导出

AMD

  • 常用于:不常用,CommonJs的浏览器端实现

  • 特点:

    异步加载:因为面向浏览器端,为了不影响渲染肯定是异步加载

    依赖前置:所有的依赖必须写在最初的依赖数组中,速度快,但是会浪费资源,预先加载了所有依赖不管你是否用到

  • 语法:

    // 1. 导出:通过define来定义模块  
    // 如果该模块还依赖其他模块,则将模块的路径填入第一个参数的数组中  
    define(['x'], function(x){  
      function foo(){  
          return x.fn()   1  
      }  
      return {  
          foo: foo  
      };  
    });  
    // 2. 引用  
    require(['a'], function (a){  
      a.foo()  
    });
    

CMD

  • 常用于:不常用,根据CommonJs和AMD实现,优化了加载方式

  • 特点:

    • 异步加载

    • 按需加载/依赖就近:用到了再引用依赖,方便了开发,缺点是速度和性能较差

  • 语法:

// 1. 导出:通过define来定义模块  
// 如果该模块还依赖其他模块,在用到的地方引用即可  
define(function(){  
  function foo(){  
      var x = require('x')  
      return x.fn()   1  
  }  
  return {  
      foo: foo  
  };  
});  
// 2. 引用  
var x = require('a');  
a.foo();

12.说说package.json中版本号的规则

版本号简介

软件版本号有四部分组成:

  • 第一部分为主版本号,变化了表示有了一个不兼容上个版本的大更改

  • 第二部分为次版本号,变化了表示增加了新功能,并且可以向后兼容

  • 第三部分为修订版本号,变化了表示有bug修复,并且可以向后兼容

  • 第四部分为日期版本号加希腊字母版本号,希腊字母版本号共有五种,分别为base、alpha、beta 、RC 、 release 

学新通

13. 说说React jsx转换成真实DOM的过程?

react通过将组件编写的JSX映射到屏幕,以及组件中的状态发生了变化之后 React会将这些「变化」更新到屏幕上

react中,节点大致可以分成四个类别:

  • 原生标签节点

  • 文本节点

  • 函数组件

  • 类组件

    createElement会根据传入的节点信息进行一个判断:

  • 如果是原生标签节点, type 是字符串,如div、span

  • 如果是文本节点, type就没有,这里是 TEXT

  • 如果是函数组件,type 是函数名

  • 如果是类组件,type 是类名

渲染流程:

  • 使用React.createElement或JSX编写React组件,实际上所有的 JSX 代码最后都会转换成React.createElement(...) ,Babel帮助我们完成了这个转换的过程。

  • createElement函数对key和ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象

  • ReactDOM.render将生成好的虚拟DOM渲染到指定容器上,其中采用了批处理、事务等机制并且对特定浏览器进行了性能优化,最终转换为真实DOM

14. 说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?

Redux 是 JavaScript 状态容器,提供可预测化的状态管理

redux 是一个状态管理工具,通常与 redux 一起使用,但是 redux 可以在任何 js 代码中使用,并不是 react 的专属工具

Redux Toolkit 提供了基于 redux 的封装,简化了 redux 创建流程及样板代码量,让我们能更加关注状态管理,同时 Redux Toolkit 附带了一些有用的工具库,例如ImmerRedux-ThunkReselect等,并且无需在手动引入 redux-devtools-extension

15. React render方法的原理,在什么时候会触发?

理解react的render函数,要从这三点来认识。原理、执行时机、总结。

在类组件和函数组件中,render函数的形式是不同的。

类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件。

render的执行时机主要分成了两部分:

类组件调用 setState 修改状态:

函数组件通过useState hook修改状态:

ender函数里面可以编写JSX,转化成createElement这种形式,用于生成虚拟DOM,最终转化成真实DOM

在React 中,类组件只要执行了 setState 方法,就一定会触发 render 函数执行,函数组件使用useState更改状态不一定导致重新render

组件的props 改变了,不一定触发 render 函数的执行,但是如果 props 的值来自于父组件或者祖先组件的 state

在这种情况下,父组件或者祖先组件的 state 发生了改变,就会导致子组件的重新渲染

所以,一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行render方法,一旦父组件发生渲染,子组件也会渲染

16. React性能优化的手段有哪些?

React凭借virtual DOMdiff算法拥有高效的性能,但是某些情况下,性能明显可以进一步提高

常见性能优化常见的手段有如下:

  • 避免使用内联函数

  • 使用 React Fragments 避免额外标记

  • 使用 Immutable

  • 懒加载组件

  • 事件绑定方式

  • 服务端渲染

17.如何通过原生js实现一个节流函数和防抖函数?

防抖当事件被触发N秒之后再执行回调,如果在N秒内被触发,则重新计时。

    <script>
      let button = document.querySelector("button");
      button.addEventListener("click", debounce(fun, 1000, true), false);
      //触发函数
      function fun(e) {
        console.log(this, "fun");
        console.log(e, "fun");
      }
      //防抖函数
      //第一次点击
      function debounce(fun, timer, trag) {
        let time = null;
        return function () {
          if (time) {
            clearTimeout(time);
          }
          if (trag) {
              //设置判断,如果是第一次就立即执行,将time转换成true
            var first = !time;
            if (first) {
              fun.apply(this, arguments);
            }
            time = setTimeout(() => {
                // 第一次立即执行过去之后将time恢复原样,然后走防抖
              time=null
            }, timer);
          } else {
            time = setTimeout(() => {
              // 函数里面不存在arguments对象,所以此时使用箭头函数,用的外层的arguments
              //通过apply方式绑定当前this指向
              fun.apply(this, arguments);
            }, timer);
          }
        };
      }
    </script>

节流:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。

 <button>提交</button>
    <script>
      let button = document.querySelector("button");
      button.addEventListener("click", debounce(fun, 1000), false);
      //触发函数
      function fun() {
        console.log(123)
      }
      //防抖函数
      //第一次点击
      function debounce(fun, delay) {
          var begin=0;
          return function(){
              var time=new Date().getTime()
              //如果当前的时间减去开始的时间大于设置的延时delay的时候再去执行
              if(time-begin>delay){
                fun.apply(this,arguments)   
                begin=time
              }
          }
       
      }
    </script>

18.说说你对koa中洋葱模型的理解?

Koa是一个精简的node框架,被认为是第二代Node框架,其最大的特点就是独特的中间件流程控制,是一个典型的洋葱模型,它的核心工作包括下面两个方面:

  1. 将node原生的req和res封装成为一个context对象。

  2. 基于async/await的中间件洋葱模型机制。

什么是洋葱模型

Koa的洋葱模型是以next()函数为分割点,先由外到内执行Request的逻辑,然后再由内到外执行Response的逻辑,这里的request的逻辑,我们可以理解为是next之前的内容,response的逻辑是next函数之后的内容,也可以说每一个中间件都有两次处理时机。洋葱模型的核心原理主要是借助compose方法。

为什么需要洋葱模型

因为很多时候,在一个app里面有很多中间件,有些中间件需要依赖其他中间件的结果,用葱模型可以保证执行顺序,如果没有洋葱模型,执行顺序可能出乎我们的预期。

19.说说如何借助webpack来优化前端性能

随着前端的项目逐渐扩大,必然会带来的一个问题就是性能

尤其在大型复杂的项目中,前端业务可能因为一个小小的数据依赖,导致整个页面卡顿甚至奔溃

一般项目在完成后,会通过webpack进行打包,利用webpack对前端项目性能优化是一个十分重要的环节

通过webpack优化前端的手段有:

  • JS代码压缩

  • CSS代码压缩

  • Html文件代码压缩

  • 文件大小压缩

  • 图片压缩

  • Tree Shaking,Tree Shaking 是一个术语,在计算机中表示消除死代码

  • 代码分离

  • 内联 chunk

关于webpack对前端性能的优化,可以通过文件体积大小入手,其次还可通过分包的形式、减少http请求次数等方式,实现对前端性能的优化

20.说说你对webSocket的理解?

什么是WebSocket

WebSocket是一种基于TCP的全双工通信协议,在应用层。

为什么需要WebSocket

1、传统上的HTTP协议它是无状态的,服务器不能够识别是哪个客户端发送的请求,不能够保存状态。
2、WebSocket弥补了这一问题,在客户端向服务端发送请求之后,服务器处理请求并返回到客户端,使用WebSocket可以使得服务器主动向浏览器推送消息

WebSocket协议的原理 与服务器进行三次握手,建立TCP连接 向服务器发送HTTP请求,请求中包含WebSocket的版本信息:包括upgrade、connection等等。 服务器处理请求并返回客户端,此时可以进行WebSocket请求了 服务端也可以主动向客户端推送消息了。

WebSocket的优缺点

优点:建立WebSocket连接之后,客户端与服务端交流更方便
     客户端只需要向服务端发送一次请求,服务端主动向客户端发送消息
缺点:在服务端的状态不会频繁变化的时候,就不需要使用WebSocket连接了,浪费性能

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgffgec
系列文章
更多 icon
同类精品
更多 icon
继续加载