react面试题总结

1、当调用 setState的时候,发生了什么操作?

当调用 setState时, React做的第一件事是将传递给setState的对象合并到组件的当前状态,这将启动一个称为和解( reconciliation)的过程。

和解的最终目标是:根据这个新的状态以最有效的方式更新DOM

为此, React将构建一个新的 React虚拟DOM树(可以将其视为页面DOM元素的对象表示方式)。

一旦有了这个DOM树,为了弄清DOM是如何响应新的状态而改变的, React会将这个新树与上一个虚拟DOM树比较

这样做, React会知道发生的确切变化,并且通过了解发生的变化后,在绝对必要的情况下进行更新DOM,即可将因操作DOM而占用的空间最小化。

2、在 React中元素( element)和组件( component)有什么区别?

简单地说,在 React中元素(虛拟DOM)描述了你在屏幕上看到的DOM元素。

换个说法就是,在 React中元素是页面中DOM元素的对象表示方式。在 React中组件是一个函数或一个类,它可以接受输入并返回一个元素。

注意:工作中,为了提高开发效率,通常使用JSX语法表示 React元素(虚拟DOM)。在编译的时候,把它转化成一个 React. createElement调用方法。

3、在构造函数调用 super 并将 props 作为参数传入的作用

  • 在构造函数里调用super的目的是:保证子类(组件里)有this

        ​ 在ES6中,super()函数就是父类的构造函数。所以,在react里定义类组件时,调用               super就是在调用React.Component的构造函数。

  • ​调用super函数时,把props传入的目的是,保证this有属性props;即:在子类(组件)里能够使用this.props

举例:

  • 传递了props
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    console.log(this.props); // { name: 'sudheer',age: 30 }
  }
}
  • 没传递 props
class MyComponent extends React.Component {
  constructor(props) {
    super();
    console.log(this.props); // undefined
    // 但是 Props 参数仍然可用
    console.log(props); // Prints { name: 'sudheer',age: 30 }
  }
  render() {
    // 构造函数外部不受影响
    console.log(this.props); // { name: 'sudheer',age: 30 }
  }
}

4、什么是 React的refs?为什么它们很重要?

refs允许你直接访问DOM元素或组件实例。为了使用它们,可以向组件添加个ref属性。

如果该属性的值是一个回调函数,它将接受底层的DOM元素或组件的已挂载实例作为其第一个参数。可以在组件中存储它。

export class App extends Component  {
    showResult ( ) {
        console. log(this. input. value)
    }
    render ( ) {
        return (
            <div>
                <input  type="text" ref={input => this .input =input } />
                < button onClick={this. showResult.bind(this)}>展示结果</ button>
            </div>
        );
    }
}

如果该属性值是一个字符串, React将会在组件实例化对象的refs属性中,存储一个同名属性,该属性是对这个DOM元素的引用。可以通过原生的 DOM API操作它。

export class App extends Component {
    showResult(){
        console .log ( this.refs.username.value)
    }
    
    render(){
        return (
            <div>
                <input type="text" ref="username"/>
                < button onClick={this. showResu1t.bind (this)}>展示结果</ button>
            </div>
        );
    }
}

5、React 中的key是什么?为什么它们很重要?

key可以帮助 React跟踪循环创建列表中的虚拟DOM元素,了解哪些元素已更改、添加或删除。

每个绑定key的虚拟DOM元素,在兄弟元素之间都是独一无二的。在 React的和解过程中,比较新的虛拟DOM树与上一个虛拟DOM树之间的差异,并映射到页面中。key使 React处理列表中虛拟DOM时更加高效,因为 React可以使用虛拟DOM上的key属性,快速了解元素是新的、需要删除的,还是修改过的。如果没有key,React就不知道列表中虚拟DOM元素与页面中的哪个元素相对应。所以在创建列表的时候,不要忽略key。

6、

7、约束性组件( controlled component)与非约束性组件( uncontrolled  component)有什么区别?

在 React中,组件负责控制和管理自己的状态。

如果将HTML中的表单元素( input、 select、 textarea等)添加到组件中,当用户与表单发生交互时,就涉及表单数据存储问题。根据表单数据的存储位置,将组件分成约東性组件和非约東性组件。

约束性组件( controlled component)就是由 React控制的组件,也就是说,表单元素的数据存储在组件内部的状态中,表单到底呈现什么由组件决定。

如下所示, username没有存储在DOM元素内,而是存储在组件的状态中。每次要更新 username时,就要调用 setState更新状态;每次要获取 username的值,就要获取组件状态值。

class App extends Component {
    //初始化状态
    constructor ( props ) {
        super ( props )
        this .state = {
         username:'有课前端网'
        }
    }
    //查看结果
    showResult ( ) {
    //获取数据就是获取状态值
        console. log ( this .state. username )
    }
    changeUsername (e) {
        //原生方法获取
        var value =e .target .value
        //更新前,可以进行脏值检测
        //更新状态
        this .setState ( {t
            username:value
        } )
    }
    //渲染组件
    render( ) {
        //返回虚拟DOM 
        return (
        <div>
            <p>
            {/*输入框绑定va1ue*/}
                <input type="text" onChange={ this.changeUsername .bind (this ) }
                value= { this .state.username }/>
            </p>
            <p>
                < button onClick={this.showResult.bind (this)}>查看结果</ button>
            </p>
        </div>
        )
    }
}

非约束性组件( uncontrolled component)就是指表单元素的数据交由元素自身存储并处理,而不是通过 React组件。表单如何呈现由表单元素自身决定。

如下所示,表单的值并没有存储在组件的状态中,而是存储在表单元素中,当要修改表单数据时,直接输入表单即可。有时也可以获取元素,再手动修改它的值。当要获取表单数据时,要首先获取表单元素,然后通过表单元素获取元素的值。

注意:为了方便在组件中获取表单元素,通常为元素设置ref属性,在组件内部通过refs属性获取对应的DOM元素。

class App extends Component {
  //查看结果
  showResult ( ) {
    //获取值
    console. log(this. refs. username .value)
   //修改值,就是修改元素自身的值
   this.refs.username.value="专业前端学习平台"
  }
  //渲染组件
  render ( ) {
    //返回虚拟DOM 
    return (
     <div>
      <p>
      {/*非约束性组件中,表单元素通过 defaultvalue定义*/}
        < input type="text"  ref=" username"  defaultvalue="有课前端网"/>
      </p>
      <p>
        < button onClick={this. showResult.bind ( this ) }>查看结果</button>
      </p>
    </div>
   )
 }

虽然非约東性组件通常更容易实现,可以通过refs直接获取DOM元素,并获取其值,但是 React建议使用约束性组件。主要原因是,约東性组件支持即时字段验证,允许有条件地禁用/启用按钮,强制输入格式等。

8、在哪个生命周期中你会发出Ajax请求?为什么?

Ajax请求应该写在组件创建期的第五个阶段,即 componentDidMount生命周期方法中。原因如下。

在创建期的其他阶段,组件尚未渲染完成。而在存在期的5个阶段,又不能确保生命周期方法一定会执行(如通过 shouldComponentUpdate方法优化更新等)。在销毀期,组件即将被销毁,请求数据变得无意义。因此在这些阶段发岀Ajax请求显然不是最好的选择。

在组件尚未挂载之前,Ajax请求将无法执行完毕,如果此时发出请求,将意味着在组件挂载之前更新状态(如执行 setState),这通常是不起作用的。

在 componentDidMount方法中,执行Ajax即可保证组件已经挂载,并且能够正常更新组件。

9、shouldComponentUpdate有什么用?为什么它很重要?

组件状态数据或者属性数据发生更新的时候,组件会进入存在期,视图会渲染更新。在生命周期方法 should ComponentUpdate中,允许选择退出某些组件(和它们的子组件)的和解过程。

和解的最终目标是根据新的状态,以最有效的方式更新用户界面。如果我们知道用户界面的某一部分不会改变,那么没有理由让 React弄清楚它是否应该更新渲染。通过在 shouldComponentUpdate方法中返回 false, React将让当前组件及其所有子组件保持与当前组件状态相同。

10、如何用 React构建( build)生产模式?

通常,使用 Webpack的 DefinePlugin方法将 NODE ENV设置为 production。这将剥离 propType验证和额外的警告。除此之外,还可以减少代码,因为 React使用 Uglify的dead-code来消除开发代码和注释,这将大大减少包占用的空间。

可以通过配置package.json中的script中的mode为production

11、为什么要使用 React. Children. map( props. children,( )=>)而不是props. children. map ( (  ) => )?

因为不能保证 props. children将是一个数组。

以下面的代码为例。

<Parent>
    <h1>有课前端网</h1>
</Parent>

在父组件内部,如果尝试使用 props.children. map映射子对象,则会抛出错误,因为props. children是一个对象,而不是一个数组。

如果有多个子元素, React会使 props.children成为一个数组,如下所示。

<Parent>
    <h1>有课前端网</h1>
    <h2>前端技术学习平台</h2>
</Parent>
不建议使用如下方式,在这个案例中会抛出错误。
class Parent extends Component {
     render ( ) {
         return (
            <div> { this .props.children.map (obj = > obj ) }</div>
        )    
    } 
}

建议使用如下方式,避免在上一个案例中抛出错误。

class Parent extends Component  {
    render ( ) {
      return (
        <div> { React.Children.map ( this .props.children, obj => obj) }</div>
    )
    }
}

12、在使用 React Router时,如何获取当前页面的路由或浏览器中地址栏中的地址?

在当前组件的 props中,包含 location属性对象,包含当前页面路由地址信息,在 match中存储当前路由的参数等数据信息。可以直接通过 this .props使用它们。

react18中可以使用useLocation获取地址相关信息

13、createElement和 cloneElement有什么区别?

  • createElement是JSX被转载得到的,在 React中用来创建 React元素(即虚拟DOM)的内容。
  • cloneElement用于复制元素并传递新的 props。

14、React- Router有几种形式?

有以下几种形式。

  • HashRouter,通过散列实现,路由要带#,不够美观。
  • BrowerRouter,利用HTML5中 history API实现,需要服务器端支持,兼容性不是很好。

15、

16、

17、React中D算法的原理是什么?

原理如下。

(1)节点之间的比较。

节点包括两种类型:一种是 React组件,另一种是HTML的DOM

如果节点类型不同,按以下方式比较:

如果 HTML DOM不同,直接使用新的替换旧的。如果组件类型不同,也直接使用新的替换旧的。

如果 HTML DOM类型相同,按以下方式比较。

在 React里样式并不是一个纯粹的字符串,而是一个对象,这样在样式发生改变时,只需要改变替换变化以后的样式。修改完当前节点之后,递归处理该节点的子节点。

如果组件类型相同,按以下方式比较:

如果组件类型相同,使用 React机制处理。一般使用新的 props替换旧的 props,并在之后调用组件的 componentWillReceiveProps方法,之前组件的 render方法会被调用。

节点的比较机制开始递归作用于它的子节点。

(2)两个列表之间的比较。

一个节点列表中的一个节点发生改变, React无法很妤地处理这个问题。循环新旧两个列表,并找出不同,这是 React唯一的处理方法。

但是,有一个办法可以把这个算法的复杂度降低。那就是在生成一个节点列表时给每个节点上添加一个key。这个key只需要在这一个节点列表中唯一,不需要全局唯一。

(3)取舍

需要注意的是,上面的启发式算法基于两点假设。

类型相近的节点总是生成同样的树,而类型不同的节点也总是生成不同的树

可以为多次 render都表现稳定的节点设置key。

上面的节点之间的比较算法基本上就是基于这两个假设而实现的。要提高 React应用的效率,需要按照这两点假设来开发。

18、概述一下 React中的事件处理逻辑。

为了解决跨浏览器兼容性问题, React会将浏览器原生事件( Browser Native Event)封装为合成事件( Synthetic Event)并传入设置的事件处理程序中。

这里的合成事件提供了与原生事件相同的接口,不过它们屏蔽了底层浏览器的细节差异,保证了行为的一致性。另外, React并没有直接将事件附着到子元素上,而是以单一事件监听器的方式将所有的事件发送到顶层进行处理(基于事件委托原理)。

这样 React在更新DOM时就不需要考虑如何处理附着在DOM上的事件监听器,最终达到优化性能的目的。

19、传入 setstate函数的第二个参数的作用是什么?

第二个参数是一个函数,该函数会在 setState函数调用完成并且组件开始重渲染时调用,可以用该函数来监听渲染是否完成

this .setstate ({ 
  username:'有课前端网'
}, ( ) => console.log ( 're-rendered success. ' ) )

20、React和vue.js的相似性和差异性是什么?

相似性如下:

  • 都是用于创建UI的 JavaScript库。
  • 都是快速和轻量级的代码库(这里指 React核心库)。
  • 都有基于组件的架构。
  • 都使用虚拟DOM。
  • 都可以放在单独的HTML文件中,或者放在 Webpack设置的一个更复杂的模块中。
  • 都有独立但常用的路由器和状态管理库。

区别:

  • react严格上只能算是MVC的view层,vue则是MVVM模式
  • 组件定义方式不同。React使用JSX语法,而Vue可以使用模板或JSX。
  • 虚拟DOM实现不同。React使用虚拟DOM进行DOM的渲染和更新,而Vue也使用虚拟DOM,但它更注重数据绑定和响应式系统。
  • 数据绑定不同。Vue实现了数据的双向绑定,而React则提倡单向数据流。
  • 社区和生态系统不同。React拥有更大的社区和更多的第三方库支持,而Vue也在社区和生态系统方面有着显著的发展。
  • 性能不同。在某些情况下,Vue可能提供更快的渲染速度,因为其在虚拟DOM和编译器方面做了一些优化。
  • 状态管理方式不同。Vue使用Vuex进行状态管理,而React则使用Redux或Context。
  • 设计理念不同。React被设计为可以自底向上逐层应用,而Vue则被设计为可以自顶向下逐层应用

21、生命周期调用方法的顺序是什么?

React生命周期分为三大周期,11个阶段,生命周期方法调用顺序分别如下。

(1)在创建期的五大阶段,调用方法的顺序如下。

  • getDetaultProps:定义默认属性数据。

  • getInitialState:初始化默认状态数据。

  • componentWillMount:组件即将被构建。

  • render:渲染组件。

  • componentDidMount:组件构建完成

(2)在存在期的五大阶段,调用方法的顺序如下。

  • componentWillReceiveProps:组件即将接收新的属性数据。

  • shouldComponentUpdate:判断组件是否应该更新。

  • componnentWillUpdate:组件即将更新。

  • render:渲染组件。

  • componentDidUpdate:组件更新完成。

(3)在销毁期的一个阶段,调用方法 componentWillUnmount,表示组件即将被销毀。

22、使用状态要注意哪些事情?

要注意以下几点。

  • 不要直接更新状态

  • 状态更新可能是异步的

  • 状态更新要合并。

  • 数据从上向下流动

23、说说 React组件开发中关于作用域的常见问题。

在 EMAScript5语法规范中,关于作用域的常见问题如下。

(1)在map等方法的回调函数中,要绑定作用域this(通过bind方法)。

(2)父组件传递给子组件方法的作用域是父组件实例化对象,无法改变。

(3)组件事件回调函数方法的作用域是组件实例化对象(绑定父组件提供的方法就是父组件实例化对象),无法改变。

在 EMAScript6语法规范中,关于作用域的常见问题如下。

(1)当使用箭头函数作为map等方法的回调函数时,箭头函数的作用域是当前组件的实例化对象(即箭头函数的作用域是定义时的作用域),无须绑定作用域。

(2)事件回调函数要绑定组件作用域。

(3)父组件传递方法要绑定父组件作用域。

总之,在 EMAScript6语法规范中,组件方法的作用域是可以改变的。

24、在 Redux中使用 Action要注意哪些问题?

在Redux中使用 Action的时候, Action文件里尽量保持 Action文件的纯净,传入什么数据就返回什么数据,最好把请求的数据和 Action方法分离开,以保持 Action的纯净。

25、在 Reducer文件里,对于返回的结果,要注意哪些问题?

在 Reducer文件里,对于返回的结果,必须要使用 Object.assign()来复制一份新的 state,否则页面不会跟着数据刷新。

return Object. assign ( { }, state, {
  type:action .type,
  shouldNotPaint : true
})

26、

27、

28、

29、如果创建了类似于下面的 Icketang元素,那么该如何实现 Icketang类?

< Icketang username="雨夜清荷">
    {user = > user ?<Info user={user} />:<Loading />}
</Icketang>
import React, { Component } fromr "react";
 export class Icketang extends Component {
//请实现你的代码
}

在上面的案例中,一个组件接受一个函数作为它的子组件。Icketang组件的子组件是一个函数,而不是一个常用的组件。这意味着在实现 Icketang组件时,需要将props. children作为一个函数来处理。

具体实现如下。

import React,  { Component } from "react";
class Icketang extends Component {
   constructor ( props ){
    super ( props ) 
    this .state = {
     user : props.user 
    }
   }
  componentDidMount( ) {
  //模拟异步获取数据操作,更新状态
    setTimeout ( ( ) => this .setstate ({
      user:'有课前端网'
     }),2000)
  }
  render ( ) {
    return this.props.children ( this .state.user )
  }
}
class Loading extends Component {
  render  ( ) {
   return <p>Loading.</p>
  }
}
class Info extends Component  { 
  render ( ) {
   return <hl> { this .props.user }</h1>
  }
}

调用 Icketang组件,并传递给user属性数据,把 props.children作为一个函数来处理。这种模式的好处是,我们已经将父组件与子组件分离了,父组件管理状态。父组件的使用者可以决定父组件以何种形式渲染子组件。

为了演示这一点,在渲染 Icketang组件时,分别传递和不传递user属性数据来观察渲染结果。

import {render} from  "react-dom";
 render (<Icketang>
    { user = > user ?<Info user = {user} /> :<Loading /> }
   </Icketang> , ickt)

上述代码没有为 Icketang组件传递user属性数据,因此将首先渲染 Loading组件,当父组件的user状态数据发生改变时,我们发现Info组件可以成功地渲染出来。

render(< Icketang user="雨夜清荷">
{ user => user ?<Info user = {user} /> :<Loading />}
</Icketang>, ickt)

上述代码为 Icketang组件传递了user属性数据,因此将直接渲染Info组件,当父组件的user状态数据发生改变时,我们发现Info组件产生了更新,在整个过程中, Loading组件都未渲染。

30、 这段代码有什么问题?

class App extends Component {
  constructor ( props )  {
    super ( props )
      this .state = {
        username:"有课前端网", 
        msg:' '
      }
  }
  render ( ) {
    return (
      <div> { this .state. msg }</div>
    );
  }
  componentDidMount ( )  {
    this .setState ( ( oldState, props ) => {
    return {
      msg:oldState .username + ' - ' + props.intro 
    }
  } )
  }

render ( < App intro=" 前端技术专业学习平台"></App>,ickt )

在页面中正常输出“有课前端网-前端技术专业学习平台”。但是这种写法很少使用,并不是常用的写法。React允许对 setState方法传递一个函数,它接收到先前的状态和属性数据并返回一个需要修改的状态对象,正如我们在上面所做的那样。它不但没有问题,而且如果根据以前的状态( state)以及属性来修改当前状态,推荐使用这种写法。

31、请说岀 React从 EMAScript5编程规范到 EMAScript6编程规范过程中的几点改变。

主要改变如下。

(1)创建组件的方法不同。

EMAScript5版本中,定义组件用 React.createClass。EMAScript6版本中,定义组件要定义组件类,并继承 Component类。

(2)定义默认属性的方法不同。

EMAScript5版本中,用 getDefaultProps定义默认属性。EMAScript6版本中,为组件定义 defaultProps静态属性,来定义默认属性。

(3)定义初始化状态的方法不同。

EMAScript5版本中,用 getInitialState定义初始化状态。EMAScript6版本中,在构造函数中,通过this. state定义初始化状态。

注意:构造函数的第一个参数是属性数据,一定要用 super继承。

(4)定义属性约束的方法不同。

EMAScript5版本中,用 propTypes定义属性的约束。

EMAScript6版本中,为组件定义 propsTypes静态属性,来对属性进行约束。

(5)使用混合对象、混合类的方法不同。

EMAScript5版本中,通过mixins继承混合对象的方法。

EMAScript6版本中,定义混合类,让混合类继承 Component类,然后让组件类继承混合类,实现对混合类方法的继承。

(6)绑定事件的方法不同。

EMAScript5版本中,绑定的事件回调函数作用域是组件实例化对象。

EMAScript6版本中,绑定的事件回调函数作用域是null。

(7)父组件传递方法的作用域不同。

EMAScript5版本中,作用域是父组件。 EMAScript6版本中,变成了null。

(8)组件方法作用域的修改方法不同。

EMAScript5版本中,无法改变作用域。

EMAScript6版本中,作用域是可以改变的。

相关推荐

  1. react面试总结

    2024-03-16 15:48:04       20 阅读
  2. react面试总结1

    2024-03-16 15:48:04       31 阅读
  3. React Native面试总结

    2024-03-16 15:48:04       40 阅读
  4. react面试总结2

    2024-03-16 15:48:04       31 阅读
  5. react面试总结3

    2024-03-16 15:48:04       36 阅读
  6. React面试总结

    2024-03-16 15:48:04       17 阅读
  7. React面试

    2024-03-16 15:48:04       33 阅读
  8. 中级React面试

    2024-03-16 15:48:04       37 阅读
  9. React面试

    2024-03-16 15:48:04       40 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-16 15:48:04       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-16 15:48:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-16 15:48:04       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-16 15:48:04       20 阅读

热门阅读

  1. c语言:一颗红心两手准备(scanf函数的返回值)

    2024-03-16 15:48:04       18 阅读
  2. 基于单片机的电梯系统模拟与研究

    2024-03-16 15:48:04       21 阅读
  3. 力扣练习题

    2024-03-16 15:48:04       18 阅读
  4. Python中sys.stdin.readline()与input()的区别

    2024-03-16 15:48:04       24 阅读
  5. 服务器硬件基础知识

    2024-03-16 15:48:04       18 阅读