详细React和node.js面试题

本文详述了React和Node.js面试中涉及的重要知识点,包括React的生命周期,15和16版本的区别,受控和非受控组件,高阶组件的两种形式,Redux的优缺点,以及React的虚拟DOM和单向数据流的优势。还涵盖了React Hooks的使用,Fiber算法,以及与Vue的对比。此外,文章还讨论了Node.js的相关内容,如文件操作,CORS设置,以及与Express的结合使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.React15生命周期及各自的作用

组件在整个 ReactJS 的生命周期中,主要会经历这4个阶段:创建阶段、实例化阶段、更新阶段、销毁阶段。

1.创建阶段:
    该阶段主要发生在创建组件类的时候,即调用 React.createClass 时触发
    这个阶段只会触发一个 getDefaultProps 方法,该方法返回一个对象并缓存起来。然后与父组件指定的 props 对象合并,最后赋值给 this.props 作为该组件的默认属性。
2.实例化阶段:
该阶段主要发生在实例化组件类的时候,也就是该组件类被调用的时候触发。这个阶段会触发一系列的流程,按执行顺序如下:
    (1).getInitialState:初始化组件的 state 的值。其返回值会赋值给组件的 this.state 属性。
    (2)componentWillMount:根据业务逻辑来对 state 进行相应的操作。
    (3)render:根据 state 的值,生成页面需要的虚拟 DOM 结构,并返回该结构。
    (4)componentDidMount:对根据虚拟 DOM 结构而生的真实 DOM 进行相应的处理。组件内部可以通过 ReactDOM.findDOMNode(this) 来获取当前组件的节点,然后就可以像 Web 开发中那样操作里面的 DOM 元素了。 
 3.更新阶段:
这主要发生在用户操作之后或者父组件有更新的时候,此时会根据用户的操作行为进行相应得页面结构的调整。这个阶段也会触发一系列的流程,按执行顺序如下:
     (1)componentWillReceiveProps:当组件接收到新的 props 时,会触发该函数。在改函数中,通常可以调用 this.setState方法来完成对 state 的修改。
     (2)shouldComponentUpdate:该方法用来拦截新的 props 或 state,然后根据事先设定好的判断逻辑,做出最后要不要更新组件的决定
     (3)componentWillUpdate:当上面的方法拦截返回 true 的时候,就可以在该方法中做一些更新之前的操作。
     (4)render:根据一系列的 diff 算法,生成需要更新的虚拟 DOM 数据。(注意:在 render 中最好只做数据和模板的组合,不应进行 state 等逻辑的修改,这样组件结构更加清晰)
     (5)componentDidUpdate:该方法在组件的更新已经同步到 DOM 中去后触发,我们常在该方法中做一 DOM 操作。
4.销毁阶段
     (1)这个阶段只会触发一个叫 componentWillUnmount 的方法。
     (2)当组件需要从 DOM 中移除的时候,我们通常会做一些取消事件绑定、移除虚拟 DOM 中对应的组件数据结构、销毁一些无效的定时器等工作。这些事情都可以在这个方法中处理。

2.react16生命周期及作用

1.组件初始化(initialization)阶段:
也就是以下代码中类的构造方法( constructor() ),Test类继承了react Component这个基类,也就继承这个react的基类,才能有render(),生命周期等方法可以使用,这也说明为什么函数组件不能使用这些方法的原因。
super(props)用来调用基类的构造方法( constructor() ), 也将父组件的props注入给子组件,功子组件读取(组件中props只读不可变,state可变)。而constructor()用来做一些组件的初始化工作,如定义this.state的初始内容。

import React, { Component } from 'react';

class Test extends Component {
  constructor(props) {
    super(props);
  }
}

2.组件的挂载(Mounting)阶段

此阶段分为componentWillMount,render,componentDidMount三个时期。
    (1).componentWillMount:
在组件挂载到DOM前调用,且只会被调用一次,在这边调用this.setState不会引起组件重新渲染,也可以把写在这边的内容提前到constructor()中,所以项目中很少用。
    (2).render:
根据组件的props和state(无两者的重传递和重赋值,论值是否有变化,都可以引起组件重新render) ,return 一个React元素(描述组件,即UI),不负责组件实际渲染工作,之后由React自身根据此元素去渲染出页面DOM。render是纯函数(Pure function:函数的返回结果只依赖于它的参数;函数执行过程里面没有副作用),不能在里面执行this.setState,会有改变组件状态的副作用。
    (3)componentDidMount:
组件挂载到DOM后调用,且只会被调用一次

3.组件的更新(update)阶段
  
此阶段分为componentWillReceiveProps,
shouldComponentUpdate,
componentWillUpdate,
render,
componentDidUpdate

   (1)componentWillReceiveProps(nextProps)
   
此方法只调用于props引起的组件更新过程中,参数nextProps是父组件传给当前组件的新props。但父组件render方法的调用不能保证重传给当前组件的props是有变化的,所以在此方法中根据nextProps和this.props来查明重传的props是否改变,以及如果改变了要执行啥,比如根据新的props调用this.setState出发当前组件的重新render

  (2)shouldComponentUpdate(nextProps, nextState)
  
此方法通过比较nextProps,nextState及当前组件的this.props,this.state,返回true时当前组件将继续执行更新过程,返回false则当前组件更新停止,以此可用来减少组件的不必要渲染,优化组件性能。

 (3)componentWillUpdate(nextProps, nextState)

此方法在调用render方法前执行,在这边可执行一些组件更新发生前的工作,一般较少用。
(4)render

根据组件的props和state(无两者的重传递和重赋值,论值是否有变化,都可以引起组件重新render) ,return 一个React元素(描述组件,即UI),不负责组件实际渲染工作,之后由React自身根据此元素去渲染出页面DOM。render是纯函数(Pure function:函数的返回结果只依赖于它的参数;函数执行过程里面没有副作用),不能在里面执行this.setState,会有改变组件状态的副作用。
(5)componentDidUpdate(prevProps, prevState)

此方法在组件更新后被调用,可以操作组件更新的DOM,prevProps和prevState这两个参数指的是组件更新前的props和state


4卸载阶段:
componentWillUnmount:

此方法在组件被卸载前调用,可以在这里执行一些清理工作,比如清楚组件中使用的定时器,清楚componentDidMount中手动创建的DOM元素等,以避免引起内存泄漏。

3.ComponentWillUnMount用来干啥

在组件被卸载并销毁之前立即被调用。在此方法中执行任何必要的清理,例如使定时器无效, 取消网络请求或清理在`componentDidMount`中创建的任何监听。

4.shouldComponentUpdate怎么优化的

shouldComponentUpdate函数是重渲染时render()函数调用前被调用的函数,它接受两个参数:nextProps和nextState,分别表示下一个props和下一个state的值。并且,当函数返回false时候,阻止接下来的render()函数的调用,阻止组件重渲染,而返回true时,组件照常重渲染。

5.componentReceiveProps什么情况下会调用

在生命周期的第一次render后不会被调用,但是会在之后的每次render中被调用 = 当父组件再次传送props。在react的update life cycle中,不得不提到 componentWillReceiveProps方法。 该方法在props被传递给组件实例时被调用

6.受控组件和非受控组件

受控组件
就形式上来说,受控组件就是为某个form表单组件添加value属性;非受控组件就是没有添加value属性的组件;,受控组件的形式如下形式:

    render:(
    return <input type="text" value="Hello!" />
    )

添加了value 属性的表单组件元素其内部是不会 维护自己状态state,组件的value值一旦设置某个具体值就始终是这个值,所以需要调用者来控制组件value的改变。
这种写法带来一个问题:渲染后的input组件的用户交互,用户输入的任何值将不起作用,input输入框中的值始终为Hello!。这与HTML中input表现不一致。
为此,为了控制该组件,就需要能能够控制input组件的值,需要借助其内部的状态state,即组件内部要维护一个状态state以便配合input组件的onChange和setState方法来完成对组件的控制;例如对上面形式可以进行封装一个inputItem组件,其内部维护一个state状态,具体代码如下:

    export default class InputItem extends React.Component{
    constructor(props){
        super(props);   
        this.state = {
        value: ""
        }
    }
    
    componentWillReceiveProps(nextProps){
        this.setState({
        value: nextProps.value
        })
    }
    
    _onChange(evt){
        this.setState({
        value: evt.target.value
        })
    }
    
    render(){
        return (
        <input type="text"
            value={this.state.value} 
            onChange={this._onChange.bind(this)}/>
        )
    }
    }

这样就可以在外部像下面这样调用InputItem组件了:

这样就可以控制react的Input组件了,其实就是需要借助react的有状态component来完成,因为有状态component可以内部维护state。
非受控组件
表现形式上,react中没有添加value属性的表单组件元素就是非受控组件。表现形式如下:

非受控组件在底层实现时是在其内部维护了自己的状态state;这样表现出用户输入任何值都能反应到元素上。
欢迎加入我们
在使用react component时,都会遇到受控组件或者非受控组件;在目前,react组件推荐使用stateless component,但是使用该形式来实现react component时使用非受控组件到倒是没有什么大问题,若是需要控制受控元素就会有出现问题,表现在:
受控组件需要主动维护一个内部state状态的,而stateless component是无需维护组件的state状态的,二者有冲突。
所以,受控元素就不能使用stateless component来创建。
鉴于受控组件与非受控组件的特点,二者应用的地方也有所不同,主要表现在:

受控元素,一般用在需要动态设置其初始值的情况;例如某些form表单信息编辑时,input表单元素需要初始显示服务器返回的某个值然后进行编辑。
非受控元素, 一般用于无任何动态初始值信息的情况; 例如form表单创建信息时,input表单元素都没有初始值,需要用户输入的情况

7. 高阶组件

一个包装了另一个基础组件的组件

拥有两种形式

a属性代理 (Props Proxy)
组件的包裹,在包裹过程中对组件进行操作,再返回,形成高阶组件
b反向继承(Inheritance Inversion)
组装,和属性代理不同的是,反向继承是继承自基础组件,它可以直接获取基础组件的props,操作基础组件的state,可以通过反向继承的形式,配合compose讲携带不同功能模块的高阶组件组装到基础组件上,加强基础组件
props的操作

这个高阶组件是一个相对简单的无状态组件,只是这个高阶组件返回了一个新的组件,而这个新的组件是对基础组件的一个包装。对基础组件的props进行了增加,也可以进行改变,删除和读取。

反向继承(Inheritance Inversion)

反向继承是继承自基础组件,并不是高阶组件继承传入的基础组件,所以成为反向继承。由于高阶组件继承了基础组件,那么高阶组件通过this可以操作基础组件的state,props以及基础组件的方法,甚至可以通过super来操作基础组件的生命周期。

a、渲染劫持

所谓渲染劫持就是,高阶组件控制了基础组件渲染生成的结果,因为基础组件的渲染被控制,高阶组件就可以对它做点什么。。。比如:

(1)、控制渲染的结果;

(2)、改变dom树的样式;

(3)、改变基础组件中一下被渲染元素的props;

(4)、操作dom树中的元素。

8. Redux的缺点:

  1. 一个组件所有的数据,必须由父组件传过来,而不能像flux中直接从store获取。
      2. 当一个组件相关数据更新时,即使父组件不需要用到这个组件,父组件还是会重新render,可能会有效率影响,需要写复杂的shouldComponentUpdate进行判断。

9. react生命周期

react的生命周期分为四个阶段:初始化阶段,更新阶段,销毁阶段,错误处理阶段(错误处理是16.3新出的) UNSFE为过时的版本

初始化阶段

  • constructor
  • static getDerivedStateFromProps//新版本才有的
  • componentWillMount( ) / UNSAFE_componentWillMount()//未来淘汰版本
  • render ()
  • componentDidmount ()

更新阶段

  • componentWillReceiveProps / UNSAFE_componentWillReceiveProps ()
  • static getDerivedStateFromprops ()
  • shouldComponentUpdate ()
  • componentWillUpdeta () / UNSAFE_componentWillUpdate ()
  • render()
  • getSnapshotBeforeUpdate ()
  • componentDidUpdate ()

销毁阶段

  • componentWillUnmount ()

错误处理

  • componentDidCatch ()

初始阶段详细

constructor//自动执行,一开始就会执行

React组件的构造函数在挂载之前被调用。在写constructor构造函数时,需要先在添加其他内容前,调用super(props),用来将父组件传来的props绑定到这个类中,使用this.props将会得到。

官方建议不要在constructor引入任何具有副作用和订阅功能的代码,这些应当使用componentDidMount()。也就是不要在这里声明或者执行事件

constructor中应当做些初始化的动作,如:初始化state,将事件处理函数绑定到类实例上,但也不要使用setState()。如果没有必要初始化state或绑定方法,则不需要构造constructor,或者把这个组件换成纯函数写法。

当然也可以利用props初始化state,在之后修改state不会对props造成任何修改,但仍然建议大家提升状态到父组件中,或使用redux统一进行状态管理。

constructor(props) {
    super(props);//不需要可以不写
    
    this.state = {
        isLiked: props.isLiked
    };
}

static getDerivedStateFromProps( nextprops )//自动执行,必须有返回值,输出参数为新值,16.3之后新出的

getDerivedStateFromProps 是react16.3之后新增,在组件实例化后,和接受新的props后被调用。他必须返回一个对象来更新状态,或者返回null表示新的props不需要任何state的更新。使用了这个钩子就不能使用 componentWillRecieveProps()

如果是由于父组件的props更改,所带来的重新渲染,也会触发此方法。
调用steState()不会触发getDerivedStateFromProps()

之前这里都是使用constructor+componentWillRecieveProps完成相同的功能的

componentWillMount()//render()前调用,可以直接同步修改state,自动执行,即将挂载组件

componentWillMount()将在React未来版本(官方说法 17.0)中被弃用。UNSAFE_componentWillMount()在组件挂载前被调用,在这个方法中调用setState()不会起作用,是由于他在render()前被调用。

为了避免副作用和其他的订阅,官方都建议使用componentDidMount()代替。这个方法是用于在服务器渲染上的唯一方法。这个方法因为是在渲染之前被调用,也是惟一一个可以直接同步修改state的地方。

render()//直接执行,必须要有的,一般返回html代码

render()方法是必需的。当他被调用时,他将计算this.propsthis.state,并返回以下一种类型:

  1. React元素。通过jsx创建,既可以是dom元素,也可以是用户自定义的组件。
  2. 字符串或数字。他们将会以文本节点形式渲染到dom中。
  3. Portals。react 16版本中提出的新的解决方案,可以使组件脱离父组件层级直接挂载在DOM树的任何位置。 
    4. null,什么也不渲染
  4. 布尔值。也是什么都不渲染。

当返回null,false,ReactDOM.findDOMNode(this)将会返回null,什么都不会渲染。

render()方法必须是一个纯函数,他不应该改变state,也不能直接和浏览器进行交互,应该将事件放在其他生命周期函数中。
如果shouldComponentUpdate()返回falserender()不会被调用。

componentDidMount() //直接执行,可以在这里进行ajax’请求,第三方实例化,拿到真实dom,写死的数据可以直接写在这里,如果是获取到的会变的数据,则需要使用定时器,不写的话函数一直在触发,会导致更新不了视图,需要在dom元素更新完之后执行

componentDidMount在组件被装配后立即调用。初始化使得DOM节点应该进行到这里。

通常在这里进行ajax请求

如果要初始化第三方的dom库,也在这里进行初始化。只有到这里才能获取到真实的dom.

更新阶段

componentWillReceiveProps () / UNSAFE_componentWillReceiveProps(nextProps)//改变state或者props时触发

官方建议使用getDerivedStateFromProps函数代替componentWillReceiveProps。当组件挂载后,接收到新的props后会被调用。如果需要更新state来响应props的更改,则可以进行this.propsnextProps的比较,并在此方法中使用this.setState()

如果父组件会让这个组件重新渲染,即使props没有改变,也会调用这个方法。

React不会在组件初始化props时调用这个方法。调用this.setState也不会触发。

shuouldComponentUpdate ( nextprops,nextstate )//参数为新的状态和属性,如果返回值为false,状态改变,视图不更新,数据改变时触发,性能优化的方法之一

调用shouldComponentUpdate使React知道,组件的输出是否受stateprops的影响。默认每个状态的更改都会重新渲染,大多数情况下应该保持这个默认行为。

在渲染新的propsstate前,shouldComponentUpdate会被调用。默认为true。这个方法不会在初始化时被调用,也不会在forceUpdate()时被调用。返回false不会阻止子组件在state更改时重新渲染。

如果shouldComponentUpdate()返回falsecomponentWillUpdate,rendercomponentDidUpdate不会被调用。

官方并不建议在shouldComponentUpdate()中进行深度查询或使用JSON.stringify(),他效率非常低,并且损伤性能。

UNSAFE_componentWillUpdate( nextprops,nextstate )//渲染新的数据时调用

在渲染新的stateprops时,UNSAFE_componentWillUpdate会被调用,将此作为在更新发生之前进行准备的机会。这个方法不会在初始化时被调用。

在这里改变数据会导致死循环,这个函数没有太大的实际作用

不能在这里使用this.setState(),也不能做会触发视图更新的操作。如果需要更新stateprops,调用getDerivedStateFromProps

getsnapshotBeforeUpdate()//新的数据渲染前调用,可以记录scroll滚动条

在react render()后的输出被渲染到DOM之前被调用。它使您的组件能够在它们被潜在更改之前捕获当前值(如滚动位置)。这个生命周期返回的任何值都将作为参数传递给componentDidUpdate()。

componentDidUpdate( prevprops,prevstate,snapshot )//第三个参数来自getSnapshopBeforeUpdate()函数的返回值

在更新发生后立即调用componentDidUpdate()。此方法不用于初始渲染。当组件更新时,将此作为一个机会来操作DOM。只要您将当前的props与以前的props进行比较(例如,如果props没有改变,则可能不需要网络请求),这也是做网络请求的好地方。

如果组件实现getSnapshotBeforeUpdate()生命周期,则它返回的值将作为第三个“快照”参数传递给componentDidUpdate()。否则,这个参数是undefined

销毁阶段

componentWillUnmount ()//连dom结构都会清除掉

在组件被卸载并销毁之前立即被调用。在此方法中执行任何必要的清理,例如使定时器无效,取消网络请求或清理在componentDidMount中创建的任何监听。

componentDidCatch(err,info)

出错时页面不会崩溃,但是会在控制台输出错误
错误边界是React组件,可以在其子组件树中的任何位置捕获JavaScript错误,记录这些错误并显示回退UI,而不是崩溃的组件树。错误边界在渲染期间,生命周期方法以及整个树下的构造函数中捕获错误。

如果类组件定义了此生命周期方法,则它将成错误边界。在它中调用setState()可以让你在下面的树中捕获未处理的JavaScript错误,并显示一个后备UI。只能使用错误边界从意外异常中恢复; 不要试图将它们用于控制流程。

错误边界只会捕获树中下面组件中的错误。错误边界本身不能捕获错误。

import React from 'react'
class Error extends React.Component {
    constructor(props) {
        super(props);
        this.state = { error: false };//定义一个错误值
    }
    
    componentDidCatch(error, info) {//错误处理函数,当错误值发生改变是触发
        console.log('错误处理-componentDidCatch')
        this.setState({ error, info });
    }
    
    errorHandle = () => {//改变错误值
        this.setState({
            error: true
        })
    }
    
    render() {
        if (this.state.error) {
            return (
                <div>
                <p> 报错了 </p>
                {
                console.log(new Error("YOLO"))
                 }
                </div>
            )
    }
    return (
        <div>
        <button onClick = { this.errorHandle }>//改变错误值
        抛出错误
        </button>
        </div>
        );
    }
}
export default Error

10. Redux-Saga

redux-saga 是一个用于管理应用程序副作用(例如异步获取数据,访问浏览器缓存等)的javascript库,它的目标是让副作用管理更容易,执行更高效,测试更简单,处理故障更容易。

redux-saga相当于一个放置在action与reducer中的垫片。

之所以称之谓副作用呢,就是为了不让触发一个action时,立即执行reducer。也就是在action与reducer之间做一个事情,比如异步获取数据等。

redux-saga使用了ES6中的Generator功能,避免了像redux-thunk的回调地狱。

11. react生命周期

初始化阶段

constructor(props)

  • React组件的构造函数在挂载之前被调用。在实现React.Component构造函数时,需要先在添加其他内容前,调用super(props),用来将父组件传来的props绑定到这个类中,使用this.props将会得到。

  • 官方建议不要在constructor引入任何具有副作用和订阅功能的代码,这些应当使用componentDidMount()

  • constructor中应当做些初始化的动作,如:初始化state,将事件处理函数绑定到类实例上,但也不要使用setState()。如果没有必要初始化state或绑定方法,则不需要构造constructor,或者把这个组件换成纯函数写法。

  • 当然也可以利用props初始化state,在之后修改state不会对props造成任何修改,但仍然建议大家提升状态到父组件中(也就是将组件的state放在其父组件中,父组件通过props将state传递给子组件,这样便于管理维护),或使用redux统一进行状态管理。

  • static getDerivedStateFromProps(nextProps, prevState)

    • getDerivedStateFromProps 是react16.3之后新增,在组件实例化后,和接受新的propsgetDerivedStateFromProps被调用。他必须返回一个对象来更新状态或者返回null表示新的props不需要任何state的更新。
    • 如果是由于父组件的props更改,所带来的重新渲染,也会触发此方法。
    • 调用steState()不会触发getDerivedStateFromProps()
    • ***之前***这里都是使用constructor+componentWillRecieveProps完成相同的功能的

    它接收两个参数

    • nextProps 即将被改变后的state值
    • prevState 自身的state值和次钩子返回的对象

    componentWillMount() / UNSAFE_componentWillMount()

    组件即将挂载

    componentWillMount()将在React未来版本(官方说法 17.0)中被弃用。UNSAFE_componentWillMount()组件挂载前被调用,在这个方法中调用setState()不会重新渲染,是由于他在render()前被调用。state在渲染前被更改了

    ? 我们通常用它进行数据请求和数据修改

    ? 假如我们将**getDerivedStateFromProps()componentWillMount()一起使用,则会出现警告,如果使用了getDerivedStateFromProps()**则相当于包含了componentWillMount()。

    是因为getDerivedStateFromProps就是用来替代componentWillMount()钩子。在未来版本中我们更应该使用getDerivedStateFromProps,而componentWillMount()更多应该是用来兼容老版本

    ?为了避免副作用和其他的订阅,官方都建议使用componentDidMount()代替。这个方法是用于在服务器渲染上的唯一方法。这个方法因为是在渲染之前被调用,也是惟一一个可以直接同步修改state的地方。

    render 虚拟DOM渲染

    render()方法是必需的。当他被调用时,他将计算this.propsthis.state,并返回以下一种类型

    1. React元素。通过jsx创建,既可以是dom元素,也可以是用户自定义的组件。
    2. 字符串或数字。他们将会以文本节点形式渲染到dom中。
    3. Portals。react 16版本中提出的新的解决方案,可以使组件脱离父组件层级直接挂载在DOM树的任何位置。
    4. null,什么也不渲染
    5. 布尔值。也是什么都不渲染。
    • 当返回null,false,ReactDOM.findDOMNode(this)将会返回null,什么都不会渲染。
    • render()方法必须是一个纯函数,他不应该改变state,也不能直接和浏览器进行交互,应该将事件放在其他生命周期函数中。
    • 如果shouldComponentUpdate()返回falserender()不会被调用。

    componentDidMount (已经生成真实Dom)

    组件挂载后调用,组件插入真实DOM树中后调用。

    componentDidMount`在组件被装配后立即调用。初始化使得DOM节点应该进行到这里。

    • 如需通过网络请求获取数据,此处是实例化请求的好地方。因为已经可以操作真实DOM
    • 通常在这里进行ajax请求
    • 依赖于 DOM 节点的初始化应该放在这里 (第三方实例化)
    • 这个方法是比较适合添加订阅的地方。如果添加了订阅,请不要忘记在 componentWillUnmount() 里取消订阅 这里可以进行事件处理,在进行事件的订阅后,需要在componentWillUnmount()取消订阅

    更新阶段

    componentWillReceiveProps(nextProps) / UNSAFE_componentWillReceiveProps(nextProps)

    当组件的props对象的属性被更改时,触发此钩子函数,通常是父组件传递数据给子属性的props,当父组件传递的数据更改时,子组件的props也更改,子组件触发此钩子函数。

    ? 注意,此钩子和getDerivedStateFromProps钩子不要一起使用。

    此钩子接收一个参数nextProps ,代表改变后的props对象

    shouldComponentUpdate(nextProps, nextState)

    • 调用shouldComponentUpdate使React知道,组件的输出是否受stateprops的影响。默认每个状态的更改都会重新渲染,大多数情况下应该保持这个默认行为。

    • 在渲染新的propsstate前,shouldComponentUpdate会被调用。默认为true这个方法不会在初始化时被调用,也不会在forceUpdate()时被调用。返回false不会阻止子组件在state更改时重新渲染。

    • 如果shouldComponentUpdate()返回falsecomponentWillUpdate,rendercomponentDidUpdate不会被调用。

    • 当props属性或者状态被更改时,将会触发此钩子,此钩子是更新阶段的必须钩子,它默认返回true,表示渲染组件props属性或state状态改变后的数据。如果我们手动设置为return false,则不会触发render渲染组件props属性或state状态改变后的数据。

    • componentWillUpdate(nextProps, nextState)/UNSAFE_componentWillUpdate(nextProps, nextState)

      在组件更新结束后触发

      • 在渲染新的stateprops时,UNSAFE_componentWillUpdate会被调用,将此作为在更新发生之前进行准备的机会。这个方法不会在初始化时被调用
      • 不能在这里使用this.setState(),也不能做会触发视图更新的操作。如果需要更新stateprops,调用getDerivedStateFromProps

      getSnapshotBeforeUpdate()

      • 当调用 getSnapshotBeforeUpdate()时,不允许有componentWillMount,componentWillReceiveProps,componentWillUpdate这三个钩子。
      • 并且它有一个返回值,这个生命周期的任何返回值都会作为参数传递给componentDidUpdate钩子的第三个参数
      • 在react render()后的输出被渲染到DOM之前被调用。它使您的组件能够在它们被潜在更改之前捕获当前值(如滚动位置)

      componentDidUpdate(prevProps, prevState, snapshot)

      在props或state更新发生后立即调用componentDidUpdate()此方法不用于初始渲染。当组件更新时,将此作为一个机会来操作DOM。只要您将当前的props与以前的props进行比较(例如,如果props没有改变,则可能不需要网络请求),这也是做网络请求的好地方。

      组件卸载阶段

      componentWillUnmount() 当组件被卸载后执行

12. react创建组件的方式

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}
同时还可以使用 ES6class 来定义组件:
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

13. react和其他框架相比有什么特点

  • react严格意义上讲只针对MVC中的view层,Vue则是MVVM模式
  • .Vitual Dom 不一样,Vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树,而react每当应用的状态被改变时,全部组件都会被渲染,所以react需要shouldComponentUpdate这个生命周期函数方法来进行控制
  • .组件写法不同,react主张jsx+inline style,也就是讲HTML、css写到js中,一切皆js,vue则是webpack+Vue-loader的单文件组件格式,即HTML、css、js组成一个文件形成.vue文件
  • 数据绑定,Vue实现了数据的双向绑定,react数据流动是单向的
  • state对象在react应用中不可变,需要使用setState方法更新状态,在Vue中,state对象不是必须的,数据由data属性在Vue对象中管理;

14. react的虚拟DOM怎么实现

步骤一:用JS对象模拟DOM树
步骤二:比较两棵虚拟DOM树的差异
步骤三:把差异应用到真正的DOM树上

15. react的单项数据流有什么优点

单向绑定的优点是相应的可以带来单向数据流,这样做的好处是所有状态变化都可以被记录、跟踪,状态变化通过手动调用通知,源头易追溯,没有“暗箱操作”。同时组件数据只有唯一的入口和出口,使得程序更直观更容易理解,有利于应用的可维护性

16.react为什么循环产生的组件中带上key这个东西?

1.react利用key来识别组件,它是一种身份标识。keys是react用于追踪哪些列表中元素     被修改、被添加或者被移除的辅助标识。
2.react根据key来决定是销毁重新创建组件还是更新组件

key相同,若组件属性有所变化,则react只更新组件对应的属性,没有变化则不更新。
    key不同,则react先销毁该组件(有状态组件的componentWillUnmount会执行),然 后重新创建该组件(constructor和componentWillUnmount都会执行)

17.react中那些情况下虚拟Dom没有真实Dom好用

  在多次操作修改单一元素属性的情况下,VirtualDom所需要的时间可能会稍微长一些。

18.在react里面会和redux绑定使用吗,redux的数据流是什么

 首先数据流是是行为与响应的抽象。
 用户在页面上输入表单、按下按钮、拖拽等行为,页面会根据用户的行为给出一些响应,
 如刷新、跳转、局部刷新、Ajax局部刷新、数据更新等。以对象、方法来把它们抽象出来,这就是数据流。
 使用数据流可以帮助我们明确行为以及行为对应的响应其次React与数据流的关系React是纯V的框架,只负责视图,把视图做成了组件化,不涉及任何的数据和控制,需要数据流进行支撑才能完成一个完整的前端项目。

19.什么时候需要引入redux

 Redux是用来统一管理状态的,项目比较复杂,很多需要全局性的变量,跨组件操作比较多就需要。如果页面不是很复杂,各个页面之间相对独立,就没必要用Redux

20.react中的setState()的理解

 - setState有两个参数
      - 第一个参数可以是一个对象
        ```javascript
          this.setState( {
            状态: 新状态值
          })
        ```
      - 第一个参数可以是一个函数,这个函数我们给起了名称,叫做 updater
        ```javascript
          this.setState( ( preState, props) => {
            return {
              状态: 新状态值
            }
          })
        ```
      - 第二个参数是一个回调函数,回调函数的目的是为了做异步
        ```javascript
           // this.setState( obj||fn,callback )

           this.setState({
             状态: 新状态值
           }, () => {
             //目的是为了异步
           })
        ```

21. react hooks的用法

React Hooks 是 React 16.7.0-alpha 版本推出的新特性, 有了React Hooks,在react 函数组件中,也可以使用类组件(classes components)的 state 和 组件生命周期。通过下面几个例子来学习React Hooks。

  • State Hook
// useState是react包提供的一个方法
import React, { useState } from "react";
import ReactDOM from "react-dom";

const Counter = () => {
  // useState 这个方法可以为我们的函数组件拥有自己的state,它接收一个用于初始 state 的值,返回一对变量。这里我们把计数器的初始值设置为0, 方法都是以set开始
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>你点击了{count}次</p>
      <button onClick={() => setCount(count + 1)}>点击</button>
    </div>
  );
};

const rootElement = document.getElementById("root");

ReactDOM.render(<Counter />, rootElement);
  • Effect Hook
// useState是react包提供的一个方法
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

const Counter = () => {
  // useState 这个方法可以为我们的函数组件拥有自己的state,它接收一个用于初始 state 的值,返回一对变量。这里我们把计数器的初始值设置为0, 方法都是以set开始
  const [count, setCount] = useState(0);
  // 类似于componentDidMount或者componentDidUpdate:
  useEffect(() => {
    // 更改网页的标题,还可以做其它的监听
    document.title = `你点击了${count}次`;
  });
  return (
    <div>
      <p>你点击了{count}次</p>
      <button onClick={() => setCount(count + 1)}>点击</button>
    </div>
  );
};

const rootElement = document.getElementById("root");

ReactDOM.render(<Counter />, rootElement);
  • React Hooks 的规则
    • 只能在顶层调用Hooks。不要在循环,条件或嵌套函数中调用Hook。
    • 不要从常规JavaScript函数中调用Hook。只在React函数式组件调用Hooks。

22.对fiber(react)了解

fiber是react 16之后发布的一种react 核心算法,React Fiber是对核心算法的一次重新实现(官网说法)。之前用的是diff算法。

在之前React中,更新过程是同步的,这可能会导致性能问题。

当React决定要加载或者更新组件树时,会做很多事,比如调用各个组件的生命周期函数,计算和比对Virtual DOM,最后更新DOM树,这整个过程是同步进行的,也就是说只要一个加载或者更新过程开始,中途不会中断。因为JavaScript单线程的特点,如果组件树很大的时候,每个同步任务耗时太长,就会出现卡顿。

React Fiber的方法其实很简单——分片。把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。

23. vue和react都有使用的吗?

  • React 和 Vue 的相同点

    1. 使用Virtual DOM,用JS模拟DOM结构,DOM变化的对比,放在JS层做,以提高重绘性能
      DOM操作昂贵,JS运行效率高,要减少DOM操作
    2. 提供了响应式(Reactive)和组件化(Composable)的视图组件。
    3. 将注意力集中保存在核心库,而将其他功能如路由和全局状态管理交给相关的库。
  • 不同之处:

    1. 性能:

      vue和React的性能都非常高,在 React 应用中,当某个组件的状态发生变化时,它会以该组件为根,重新渲染整个组件子树。如要避免不必要的子组件的重渲染,你需要手动实现;在 Vue 应用中,组件的依赖是在渲染过程中自动追踪的,所以系统能精确知晓哪个组件确实需要被重渲染,开发者不需要考虑组件是否需要重新渲染之类的优化。
      
    2. HTML & CSS

      在React中,一切都是JavaScript,所有的组件的渲染功能都依靠 JSX。JSX 是使用 XML 语法编写 JavaScript 的一种语法糖。你可以使用完整的编程语言 JavaScript 功能来构建你的视图页面;在Vue中有自带的渲染函数,Vue也支持JSX,Vue官方推荐使用模板渲染视图。组件分为逻辑类组件和表现类组件。
      
    3. 组件作用域内的 CSS

      CSS 作用域在 React 中是通过 CSS-in-JS 的方案实现的 (比如 styled-components、glamorous 和 emotion);在Vue中是通过给style标签加scoped标记实现的。
      
    4. 规模

      Vue 的路由库和状态管理库都是由官方维护支持且与核心库同步更新的。React 则是选择把这些问题交给社区维护,因此创建了一个更分散的生态系统。但相对的,React 的生态系统相比 Vue 更加繁荣。
      
    5. 原生渲染

      React Native 能使你用相同的组件模型编写有本地渲染能力的 APP (iOS 和 Android)。能同时跨多平台开发,对开发者是非常棒的。
      

24. react 16与15的区别?

  1. React 15 到 16 生命周期函数变动

    预废弃:

    componentWillMount,componentWillUpdate,componentWillReceiveProps

    已新增:

    static getDerivedStateFromProps(props, state) 
    getSnapshotBeforeUpdate(prevProps, prevState)
    
    UNSAFE_componentWillMount 
    UNSAFE_componentWillReceiveProps 
    UNSAFE_componentWillUpdate
    

    到目前为止(React 16.4),React的渲染机制遵循同步渲染:

    1. 首次渲染: willMount > render > didMount,
    2. props更新时: receiveProps > shouldUpdate > willUpdate > render > didUpdate
    3. state更新时: shouldUpdate > willUpdate > render > didUpdate
    4. 卸载时: componentWillUnmount()
  2. react 16 没有 diff 算法

    diff 算法是递归算法,react 16 没有递归,没有树,改为一条 三向链表

    react 16 所谓的 diff 只是新旧 fiber 节点的简单比对,不需要算法

  3. 更小的资源
    react+react dom打包之后 相较于上一个版本大小减少了约30%

  4. 更强的渲染性能
    React 16是第一个对React核心代码进行了重构命名为React Fiber,Fiber 相较于之前最大的不同是它可以支持异步渲染,异步渲染的意义在于能够将渲染任务划分为多块。浏览器的渲染引擎是单线程的,这意味着几乎所有的行为都是同步发生的。React 16 使用原生的浏览器 API 来间歇性地检查当前是否还有其他任务需要完成,从而实现了对主线程和渲染过程的管理,这块具体的逻辑比较复杂,想要深入研究的可以参照React Fiber的源码。

    笔者尝试了将原来频繁setState的场景,例如拖动效果:

    onTouchMove(e) {
       let po = this.getPosition(e);
        this.setState({
            top: po.y,
            left: po.x
        });
    }
    

    切换到React 16之后在某些低端机型上的拖动体验要比之前好一些,关于前端的渲染性能有待进一步的数据验证。

  5. 服务端渲染性能的提升
    React 16的SSR被完全重写,新的实现非常快,接近3倍性能于React 15,现在提供一种流模式streaming,可以更快地把渲染的字节发送到客户端。关于服务端性能渲染的数据有待和直出共同端统计:升级前后内存占用量对比 (蓝线升级后 绿线升级前)减低10% 的cpu内存使用量

  6. render方法支持返回数组
    之前使用React时,会经常遇到的一个问题就是在返回多余一个组件时要使用一个div包裹起来在升级之后就可以直接返回一个数组:

    render(){
      return [
        <div key="1">1</div>,
        <span key="2">2</span>,
        <p key="3">3</p>
      ]
    }
    
  7. 更强的错误处理机制
    在React 15的时候,react的错误处理机制借助unstable_handleError来处理异常,这个有局限性也不是很好用,React 16将这一功能进行了升级,新增了组件生命周期的componentDidCatch方法:

  8. React 16不再支持采用es5写法定义的Component例如:

var Main = React.createClass({
    render: function () {
        return null;
    }
});

25. react16中getSnapshotBeforeUpdate返回值,return null的情况?

getSnapshotBeforeUpdate生命周期在更新之前被调用(例如,在DOM被更新之前)。此生命周期的返回值将作为第三个参数传递给componentDidUpdate。返回null则为不返回任何东西

26. react组件化的了解

react的最大的特性就是组件化,组件化的目的就是为了能够进行代码的复用,减少代码的冗余

组件化的本质,其实就是面向对象的设计思想。组件化可以对应于 一个类,每个类都对外输出不变的接⼝,只要接⼝不变,类与类间 的通讯可以根据接⼝进行,由此不同组件间的耦合度就降低了。 同时复杂的类可以通过若干个简单的类组合而成,这样一来,不但 可以提高组件的重用性,同时通过组合的思想来设计复杂的控件, 也极大的降低了复杂控件的设计难度

原文:https://blog.youkuaiyun.com/jane617_min/article/details/79573019

27.设计一个组件的方法?如何实现?

已知组件无状态组件,类组件。

28.react如何实现权限管理

https://blog.hypers.io/2017/07/22/react-permission/

29 公司中是否有react npm私有仓库?怎么开发公共组件的

https://blog.youkuaiyun.com/fghsfeyhdf/article/details/88596427

31.bable底层原理是什么?

  • Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码
  • 和编译器类似,babel 的转译过程也分为三个阶段
    解析 Parse
    将代码解析生成抽象语法树( 即AST ),也就是计算机理解我们代码的方式(扩展:一般来说每个 js 引擎都有自己的 AST,比如熟知的 v8,chrome 浏览器会把 js 源码转换为抽象语法树,再进一步转换为字节码或机器代码),而 babel 则是通过 babylon 实现的 。简单来说就是一个对于 JS 代码的一个编译过程,进行了词法分析与语法分析的过程。
    转换 Transform
    对于 AST 进行变换一系列的操作,babel 接受得到 AST 并通过 babel-traverse 对其进行遍历,在此过程中进行添加、更新及移除等操作。
    生成 Generate
    将变换后的 AST 再转换为 JS 代码, 使用到的模块是 babel-generator。

32.使用过webpack里面哪些plugin和loader

常见的loader
1.loaders之预处理
  • css-loader 处理css中路径引用等问题
  • style-loader 动态把样式写入css
  • sass-loader scss编译器
  • less-loader less编译器
  • postcss-loader scss再处理
2.loader的 js处理
  • babel-loader:转化ES6代码
  • jsx-loader:识别js中的 jsx 语法
3.其他loader加载器
  • url-loader: 图片处理 npm install --save-dev url-loadr
  • file-loader: 文件加载 npm install --save-dev file-loader
  • json-loader:json处理 npm install --save-dev json-loader
  • raw-loader: html处理 npm install --save-dev raw-loader
常见的plugin
  • 1.DedupePlugin
    打包的时候删除重复或者相似的文件
  • 2.MinChunkSizePlugin
    把多个小模块进行合并,以减少文件的大小
  • 3.UglifyJsPlugin
    压缩js
  • 4.HtmlWebpackPlugin
    生成html
  • 5.CommonsChunkPlugin
    多个 html共用一个js文件(chunk)

33.webpack里面的插件是怎么实现的

webpack 插件是由「具有 apply 方法的 prototype 对象」所实例化出来的。这个 apply 方法在安装插件时,会被 webpack compiler 调用一次。apply 方法可以接收一个 webpack compiler 对象的引用,从而可以在回调函数中访问到 compiler 对象。
一个webpack000插件有以下特性
+ 本质是一个构造函数
+ 原型prototype实现了apply方法,可以通过参数注入compiler对象
+ 可以在compiler的钩子里面获取compilation对象

34.webpack中loader的原理是什么

由于webpack是基于Node的所以webpack只能识别.js文件,所以针对其他的文件就需要转译,这时候就需要用到我们的loader了。
loader是文件加载器,能够加载资源文件,并对这些文件进行特定的处理,然后打包的指定文件中,简单来说就是将webpack传入的字符串做出特定的处理修改。

35.nodejs如何设置cors?

使用cors这个模块可以实现跨域的功能

在express项目下面
执行npm install cors
然后在app.js里面
var cors = require(‘cors’);
app.use(cors());

36.Node.js用过没,主要用来做什么?

​```
node.js是一个运行在chromeJavascript运行环境下(俗称GoogleV8引擎)的开发平台,用来方便快捷的创建服务器端网络应用程序。你可以把它理解为一个轻量级的JSP或PHP环境,但是用来开发Web应用的话,有时要便捷很多。

​```

37.使用Node.js做过什么,有真实项目经历吗

运用node.js模拟过学生管理系统,数据表使用的是Mongo。后端使用的是node.js,采用事件驱动和异步编程。且Node.js非阻塞模式的IO处理给Node.js带来在相对低系统资源耗用下的高性能与出众的负载能力,非常适合用作依赖其它IO资源的中间层服务 ​

38.Node.js用于文件操作的模块是哪个:

是fs模块: 具有文件读和写操作: fs.readFile, fs.writeFile ​

39.fs中获取文件路径哪个API,还有其他操作API吗?

​```
fs.readFile(path[,options],callback)

​```

40.nodejs的了解

1.Node.js是一个基于Chrome V8引擎的javascipt的运行环境。 2. Node.js使用了一个事件驱动、非阻塞I/O的模型, 3. Node.js轻量又高效,能够使我们在本地运行javascript 4.Node.js采用一系列“非阻塞”库来支持事件循环的方式。本质上就是为文件系统、数据库之类的资源提供接口。 5. Node.js使用事件驱动,非阻塞I/O模型而得以轻量和高效,非常适合在分布式设备上运行数据密集型的实时应用。 6.node.js是平台,JavaScript是编程语言; 7.javascript是客户端编程语言,需要浏览器的javascript解释器进行解释执行; 8.node.js是一个基于Chrome JavaScript运行时建立的平台,它是对Google V8引擎进行了封装的运行环境; 9.node.js就是把浏览器的解释器封装起来作为服务器运行平台,用类似javascript的结构语法进行编程,在node.js上运行。 ​

41.path.join与path.resolve的区别

​```
path.join():
path.join()方法可以连接任意多个路径字符串。要连接的多个路径可做为参数传入。
path.join()方法在接边路径的同时也会对路径进行规范化

path.resolve():

path.resolve()方法可以将多个路径解析为一个规范化的绝对路径。其处理方式类似于对这些路径逐一进行cd操作,与cd操作不同的是,这引起路径可以是文件,并且可不必实际存在(resolve()方法不会利用底层的文件系统判断路径是否存在,而只是进行路径字符串操作)
​```xxxxxxxxxx path.join():path.join()方法可以连接任意多个路径字符串。要连接的多个路径可做为参数传入。path.join()方法在接边路径的同时也会对路径进行规范化path.resolve():​path.resolve()方法可以将多个路径解析为一个规范化的绝对路径。其处理方式类似于对这些路径逐一进行cd操作,与cd操作不同的是,这引起路径可以是文件,并且可不必实际存在(resolve()方法不会利用底层的文件系统判断路径是否存在,而只是进行路径字符串操作)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值