React面试题,全全全!!!(全家桶)

创建react项目命令:

npx create-react-app my-app

进入文件夹:

cd my-app

启动项目:

npm start(开发模式下运行)
npm test(测试环境运行)
npm run build(打包为生产模式)

显示配置文件:不可逆的,只要显示了就没有任何方法再隐藏回去

npm run eject

 为什么在src创建子目录?

webpack只处理src的中的文件。如果不讲css和html放在src文件夹下,webpack发现不了

react是单页面应用程序

1.React是什么?

用来构造用户界面的JS库

2.React有什么特点?

它用于虚拟DOM,组件化设计模式,声明式代码,单向数据流,使用jsx描述信息等特点

3.什么是虚拟DOM?

用于构建虚拟的HTML的DOM

虚拟DOM可以看做是一棵模拟DOM树的js对象树。例如:

var element = {
    element: 'ul',
    props: {
        id:"ulist"
    },
    children: [
    { element: 'li', props: { id:"first" }, children: ['这是第一个List元素'] },
    { element: 'li', props: { id:"second" }, children: ['这是第二个List元素'] }
    ]
}

4.为什么要使用虚拟DOM?

传统的数据只要发生变化,就会引起DOM重新渲染。虚拟DOM的目的是将所有操作累加起来,统计计算出所有的变化后,统一更新一次DOM。

5.什么是组件化设计模式?

可复用的代码可以抽成组件共同使用(UI,方法等) 

6.声明式代码(编程)思想:

就是你的目的是什么,应该怎么做,但是具体不说明怎么去做

举例子:去酒吧告诉服务员你要一杯鸡尾酒,服务员把做好的鸡尾酒给你,并没有说做的过程是怎样的

const toLowerCase = arr = arr.map(
    value => value.toLowerCase();
)

7.还有其他的编程方式吗?

命令式编程

就是描述代码如何工作,告诉计算机一步步的执行,先做什么后做什么。

举例子:去酒吧点一杯酒,指挥服务员

  • 从架子上取下一个玻璃杯
  • 把杯子放在酒桶前
  • 打开酒桶开关,直到酒杯杯满
  • 把做好的鸡尾酒递给顾客
const toLowerCase = arr => {
    const res = [];
    for (let i = 0, len = arr.length; i < len; i++) {
        res.push(arr[i].toLowerCase());
    }
    return res;
}

8.编程式和命令式的对比

  • 简洁,易懂,利于大型项目代码的维护
  • 无须使用变量,避免了创建和修改状态 

9.什么是单向数据流 

数据主要从父节点传到子节点(通过props),如果父级的某个props改变了,React会重新渲染所有子节点像瀑布的水一样,从上往下流,这个水就是组件的数据流。

// 父组件
import React, {Component} from 'react'
import Child from './Child'
class Parent extends Component{   
    // 初始化
    constructor(props){
        super(props)
        this.state = {
            message: '我是从父组件传过来的'
        }
    } 
    // 渲染
    render(){
        return(
            <div>
                <Son msg={this.state.message}/>
            </div>
        )
    }
}
export default Parent


// 子组件
import React, {Component} from 'react'
class Child extends Component{  
    // 初始化
    constructor(props){
        super(props)
    } 
    // 渲染
    render(){
        return(
            <div>
               {this.props.message}
            </div>
        )
    }
}
export default Child

10.什么是JSX呢?JSX代码到显示内容的转换过程

JSX就是JS的扩展语言(jsx语法= js语法+xml(html)语法)

JSX是JavaScript XML的缩写,是JavaScript的语法扩展,本质上是JavaScript对象。JSX可以很好的描述UI信息,但是浏览器无法直接读取,编译过程中会将JSX转换成JS的语法。

11.react的主要功能有哪些?

  • 它使用虚拟DOM,而不是真正的DOM
  • 它遵循单向数据流

12.react的优缺点

优点:

  • 提高了应用性能和开发效率
  • 使用JSX,代码可读性好
  • react的componentWillUnmount生命周期,能够清除相关所有事件,避免内存泄露
  • 并不直接对DOM进行操作,引入了一个虚拟DOM的概念,安插在js和真实DOM中间,性能好,速度快 

缺点:每次 state 更改,render 函数都要生成完整的虚拟 DOM. 哪怕 state 改动很小,render函数也会完整计算一遍。如果 render 函数很复杂,这个过程就白白浪费了很多计算资源

https://blog.csdn.net/weixin_42052388/article/details/80902388

13.VUE与React两个框架的区别对比 

相似之处:

  • 用于创建UI的js库
  • 使用起来轻快便捷
  • 都用了虚拟DOM
  • 都是基于组件的架构 

不同点 :

  • vue使用的html模板;react使用的是js
  • vue有双向绑定语法
  • vue增加了语法糖computed和watch等,react需要自己写逻辑来实现
  • react用了jsx语法
  • react整体思路是编程式,推荐组件化,数据不变,单向数据流;vue数据可变,双向绑定,声明式的写法

14.React的工作原理  

React会创建一个虚拟的DOM。当一个组件的状态改变时,React首先会通过“diffing"算法来标记虚拟DOM中的改变,第二步是调节,会用diff的结果来更新DOM.

15.Real DOM和Virtual DOM 

React不直接操作DOM,而是实现了Virtual DOM,组件DOM映射到这个虚拟DOM上。React在虚拟DOM上实现了differ算法,当要重新渲染组件的时候,会通过diff寻找到要变更的DO0M节点,再把这个修改更新到浏览器实际的DOM节点上。 

17.为什么虚拟DOM会提高性能 

虚拟DOM相当于在JS和真实DOM中间加了一个缓存,利用diff减少了没有必要的操作,从而提高性能,本质上是JS对象。

  • 虚拟DOM是映射真实DOM的js对象数据结构
  • 采用虚拟DOM,避免直接操作真实的DOM,提供性能
  •  当状态更新时,重新渲染新的虚拟DOM,采用diff算法对比新旧DOM,进行更新

18.阻止React的默认行为  

e.preventDefault()    e是第三方提供的一个合成事件

注意:不能用return

class App extends React.component{
constructor(props){
super(props);
this.state = {
}
}

hander(e){
e.preventDefault()
}
render(){
return <button onClick={ this.hander.bind(this) }>阻止事件</button>
}
}

19.向事件处理程序传递参数 

例如删除当前行的ID

<button onClick={(e) => this.delete(e,id)}>Delete Row<button>
<button onClick={this.delete.bind(this,id)}>Delete Row</button>

 20.React中key作用是什么? 

 作用(目的):key是用于追踪那些列表中元素被修改,删除或者被添加的辅助标识。在diff算法中,key用来判断该元素节点是被 移动过来的还是新创建元素,减少不必要的元素重复渲染。

21.当渲染一个列表时,何为 key?

Keys 会有助于 React 识别哪些 items 改变了,被添加了或者被移除了。Keys 应该被赋予数组内的元素以赋予(DOM)元素一个稳定的标识,选择一个 key 的最佳方法是使用一个字符串,该字符串能惟一地标识一个列表项。很多时候你会使用数据中的 IDs 作为 keys,当你没有稳定的 IDs 用于被渲染的 items 时,可以使用项目索引作为渲染项的 key,但这种方式并不推荐,如果 items 可以重新排序,就会导致 re-render 变慢。

22.React中diff算法 

diff算法的作用是用来计算出Virtual DOM中被改变的部分,然后针对该部分进行原生DOM操作,而不用重新渲染整个页面。

https://www.cnblogs.com/yumingxing/p/9438457.html

diff算法有3种策略:

  • tree diff:DOM节点跨层级的移动操作特别少,可以忽略不计。
  • component diff:拥有相同类的两个组件生成相似的数据结构;拥有不同类的两个组件生成不同的树形结构
  • element diff:对于同一层级的一组子节点,通过唯一id区分

diff算法的原理

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

 23.React中Element与Component

Element是描述屏幕上课件内容的数据结构,是对UI对象的标书

Component是可以接受参数输入并且返回某个ReactElement的函数或者类

24.props和state((组件的)状态(state)和属性(props)之间有何不同)

  • state是数据结构,会随着事件推移发送变化,只能使用setState来改变
  • props是组件的属性,由父组件传递给子组件,props是不可以改变的 

state是局部的,除了它所在的这个组件其它组件都无法访问

  • 无状态组件:没有设置state的组件(无状态组件通过函数式声明来构建,一个函数就是一个组件)
  • 有状态组件:设置了state的组件(有状态组件通过component来构建,一个子类就是一个组件)

25.React可以用两种方法声明组件(Component),他们的区别是什么,什么情况你会选择哪一种?(React中有哪些构建组件的方式)  

  •  函数组件:首字母要大写,需要return出react元素
  • 类组件(Class Components):首字母要大写,需要使用render方法,return出react元素
// 函数组件
function Welcome(props){
return (
<h1>hello world</h1>
)
}


// 类组件
class Welcome extends React.Component{
        render(){
            return (
            <div>11</div>
        )
    }
}

区别:

  • 函数组件看似只是一个返回值是DOM结构的函数,其实它的背后是无状态组件的思想
  • 函数组件中,你无法使用State,也无法使用组件的生命周期方法,这就决定了函数组件都是展开性组件,接收props,渲染DOM,而不关注其它逻辑
  • 函数组件中没有this
  • 函数组件更容易理解。当你看到一个函数组件时,你就知道它的功能只是接收属性,渲染页面,它不执行与UI无关的逻辑处理,它只是一个纯函数。而不用在意它返回的DOM结构有多复杂

26.React组件生命周期的阶段是什么?

React 组件的生命周期有三个不同的阶段:

  1. 初始渲染阶段:这是组件即将开始其生命之旅并进入 DOM 的阶段。
  2. 更新阶段:一旦组件被添加到 DOM,它只有在 prop 或状态发生变化时才可能更新和重新渲染。这些只发生在这个阶段。
  3. 卸载阶段:这是组件生命周期的最后阶段,组件被销毁并从 DOM 中删除。

27.简单聊聊生命周期(指出(组件)生命周期方法的不同)

  • constuctor:在构造函数中初始化props和state
  • componentWillMount--在组件渲染之前执行,对state进行最后的修改
  • render:渲染
  • componentDidMount-- 在组件渲染之后执行
  • componentWillReceiveProps -- 这个周期函数作用于特定的 prop 改变导致的 state 转换
  • shouldComponentUpdate -- 用来做性能优化的,根据特定条件返回 true 或 false。如果你希望更新组件,请返回true 否则返回 false。默认情况下,它返回 false。
  • componentWillUpdate -- 数据在改变之前执行
  • componentDidUpdate -- 渲染发生后立即调用
  • componentWillUnmount -- 从 DOM 卸载组件后调用。用于清理内存空间

28.什么是单向数据流和状态提升

  • 单向数据流:从上往下父组件将state数据流向子组件,子组件通过props取值(像瀑布的水一样,从上往下流,这个水就是组件的数据流)
  • 状态提升:组件之间的数据交互(很多子组件想用这个状态,将这个状态提升到最上面,通过props谁用给谁)

举例子:如果两个组件都需要用到对方的状态,那么这时候就可以用到状态提升。具体做法是把两个子组件的状态写到他们的父组件中,然后父组件把状态传递给子组件的props中去,这样子组件也相当于有状态。

父组件

import React from "react"
import Child1 from "./child1"
import Child2 from "./child2"

export default class Parent extends React.Component {

    constructor() {
        super()
        this.state = {
            money: 1
        }
    }

    changeHander(e){
        this.setState({
            money: e.target.value
        })
    }
    render() {
        return (
            <div>
                <input type="text" value={ this.state.money } onChange={this.changeHander.bind(this)} />
                <p>Parent</p>
                人民比: <Child1 money={this.state.money} />
                美金: <Child2 money={this.state.money} />
            </div>
        )
    }
}

 子组件1

import React from "react"

export default class Child1 extends React.Component{

    constructor(){
        super()
        this.state = {
            input1: 0
        }
    }

    componentDidMount(){
        this.setState({
            input1: this.props.money
        })
    }

    changeHander(e) {
        this.setState({
             input1: e.target.value
        })
    }

    render() {
        return(
            <div>
                 { this.props.money }
               <input type="text" value={ this.state.input1 } onChange={ this.changeHander.bind(this) }/>
            </div>
        )
    }
}

 子组件2

import React from "react"

export default class Child2 extends React.Component{

    constructor(){
        super();
        this.state = {
            input2: 1
        }
    }

    componentDidMount(){
        this.setState({
            input2: this.props.money * 7
        })
    }

    changeHander(e) {
        this.setState({
             input2: e.target.value
        })
    }
    render() {
        return(
            <div>
                { this.props.money * 7}
               <input type="text" value={ this.state.input2 } onChange={ this.changeHander.bind(this) }/>
            </div>
        )
    }
}

29.调用setState之后发生了什么

setState会进行状态更新

将传入的参数对象与组件当前状态合并,然后触发所谓的调和过程,经过调和过程,根据新的state,React元素会重新构建虚拟DOM,进行diff算法对比新旧虚拟DOM树的区别,进行视图更新,而不是全部渲染。

setState 采用的任务队列机制,不会马上执行,而是加入队列,在下次事件循环是一次性执行

30.为什么建议传递给setState的参数是一个callback(回调函数)而不是一个对象(不懂--先不用背)

因为this.props和this.state的更新可能是异步的,不能依赖他们的值去计算下一个state

31.关于this绑定==组件绑定点击事件

// bind
// 1
<button onClick={this.handleClick.bind(this)}>hello<button/>
// 2
clicked(param,event){
    console.log(param) //hello world
    console.log(event.target.value) //按钮
}
render(){
    return (
        <React.Fragment>
            <button value="按钮" onClick={this.clicked.bind(this,"hello world")}>点击</button>
        </React.Fragment>
    )
}


// 2.在构造函数中默认绑定this(推荐)
this.handleClick = this.handleClick.bind(this)

// 3.使用箭头函数来处理,handleClick点击事件的方法
<button onClick={(e) => this.handleClick(e)}>Click me</button>

32.setState第二个参数的作用 (不懂-不用背)

该函数会在setState函数调用完成并且组件开始重渲染的时候被调用,我们可以用该函数来监听渲染是否完成

(在构造函数中)调用 super(props) 的目的是什么

 在 super() 被调用之前,子类是不能使用 this 的,在 ES5 中,子类必须在 constructor 中调用 super()。传递 props 给 super() 的原因则是便于(在子类中)能在 constructor 访问 this.props

33.什么是React 路由?

Router 用于定义多个路由,当用户定义特定的 URL 时,如果此 URL 与 Router 内定义的任何 “路由” 的路径匹配,则用户将重定向到该特定路由。

import React from 'react';
import { Switch, Route, BrowserRouter } from 'react-router-dom';
import Home from './views/Home'

export default class App extends React.Component{
    // 初始化
    constructor(props){
        super(props);
        this.state = {}
    }
    // 渲染
    render(){
        return(
           <BrowserRouter>
               <Switch>
                   <Route component={Home} path="/" />
               </Switch>
           </BrowserRouter>
        )
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40055200/article/details/108549121