35 道我们必需要清楚的 React 面试题

做者:Alexhtml

译者:前端小智前端

来源:dev.tonode


上个月本身花了 1300 买了阿(a)里(li)的 服 务 器来学习 node 及对应的框架,在 11 号以前它们有作活动,1300 的配置如今一年只要 86 元,三年只要229元,真心以为很划算了,能够点击本条内容进行参与react


问题1:什么是虚拟DOM?

主题: Reactwebpack

难度: ⭐git

虚拟 DOM (VDOM)是真实 DOM 在内存中的表示。UI 的表示形式保存在内存中,并与实际的 DOM 同步。这是一个发生在渲染函数被调用和元素在屏幕上显示之间的步骤,整个过程被称为调和github

问题2:类组件和函数组件之间的区别是啥?

主题: Reactweb

难度: ⭐⭐算法

  • 类组件可使用其余特性,如状态 state 和生命周期钩子。数组

  • 当组件只是接收 props 渲染到页面时,就是无状态组件,就属于函数组件,也被称为哑组件或展现组件。

函数组件和类组件固然是有区别的,并且函数组件的性能比类组件的性能要高,由于类组件使用的时候要实例化,而函数组件直接执行函数取返回结果便可。为了提升性能,尽可能使用函数组件。

区别 函数组件 类组件
是否有 this 没有
是否有生命周期 没有
是否有状态 state 没有

问题 3:React 中 refs 干吗用的?

主题: React

难度: ⭐⭐

Refs 提供了一种访问在render方法中建立的 DOM 节点或者 React 元素的方法。在典型的数据流中,props 是父子组件交互的惟一方式,想要修改子组件,须要使用新的pros从新渲染它。凡事有例外,某些状况下我们须要在典型数据流外,强制修改子代,这个时候可使用 Refs

我们能够在组件添加一个 ref 属性来使用,该属性的值是一个回调函数,接收做为其第一个参数的底层 DOM 元素或组件的挂载实例。

class UnControlledForm extends Component {
  handleSubmit = () => {
    console.log("Input Value: ", this.input.value)
  }
  render () {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type='text'
          ref={(input) => this.input = input} />
        <button type='submit'>Submit</button>
      </form>
    )
  }
}
复制代码

请注意,input 元素有一个ref属性,它的值是一个函数。该函数接收输入的实际 DOM 元素,而后将其放在实例上,这样就能够在 handleSubmit 函数内部访问它。

常常被误解的只有在类组件中才能使用 refs,可是refs也能够经过利用 JS 中的闭包与函数组件一块儿使用。

function CustomForm ({handleSubmit}) {
  let inputElement
  return (
    <form onSubmit={() => handleSubmit(inputElement.value)}>
      <input
        type='text'
        ref={(input) => inputElement = input} />
      <button type='submit'>Submit</button>
    </form>
  )
}
复制代码

问题 4:在 React 中如何处理事件

主题: React

难度: ⭐⭐

为了解决跨浏览器的兼容性问题,SyntheticEvent 实例将被传递给你的事件处理函数,SyntheticEvent是 React 跨浏览器的浏览器原生事件包装器,它还拥有和浏览器原生事件相同的接口,包括 stopPropagation()preventDefault()

比较有趣的是,React 实际上并不将事件附加到子节点自己。React 使用单个事件侦听器侦听顶层的全部事件。这对性能有好处,也意味着 React 在更新 DOM 时不须要跟踪事件监听器。

问题 5:state 和 props 区别是啥?

主题: React

难度: ⭐⭐

propsstate是普通的 JS 对象。虽然它们都包含影响渲染输出的信息,可是它们在组件方面的功能是不一样的。即

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

问题 6:如何建立 refs

主题: React

难度: ⭐⭐

Refs 是使用 React.createRef() 建立的,并经过 ref 属性附加到 React 元素。在构造组件时,一般将 Refs 分配给实例属性,以即可以在整个组件中引用它们。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}
复制代码

或者这样用:

class UserForm extends Component {
  handleSubmit = () => {
    console.log("Input Value is: ", this.input.value)
  }
  render () {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type='text'
          ref={(input) => this.input = input} /> // Access DOM input in handle submit
        <button type='submit'>Submit</button>
      </form>
    )
  }
}
复制代码

问题 7:什么是高阶组件?

主题: React

难度: ⭐⭐

高阶组件(HOC)是接受一个组件并返回一个新组件的函数。基本上,这是一个模式,是从 React 的组合特性中衍生出来的,称其为纯组件,由于它们能够接受任何动态提供的子组件,但不会修改或复制输入组件中的任何行为。

const EnhancedComponent = higherOrderComponent(WrappedComponent);
复制代码

HOC 能够用于如下许多用例

  • 代码重用、逻辑和引导抽象
  • 渲染劫持
  • state 抽象和操做
  • props 处理

问题 8:在构造函数调用 super 并将 props 做为参数传入的做用是啥?

主题: React

难度: ⭐⭐

在调用 super() 方法以前,子类构造函数没法使用this引用,ES6 子类也是如此。将 props 参数传递给 super() 调用的主要缘由是在子构造函数中可以经过this.props来获取传入的 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 }
  }
}
复制代码

上面示例揭示了一点。props 的行为只有在构造函数中是不一样的,在构造函数以外也是同样的。

问题 9:什么是控制组件?

主题: React

难度: ⭐⭐⭐

在 HTML 中,表单元素如 <input><textarea><select>一般维护本身的状态,并根据用户输入进行更新。当用户提交表单时,来自上述元素的值将随表单一块儿发送。

而 React 的工做方式则不一样。包含表单的组件将跟踪其状态中的输入值,并在每次回调函数(例如onChange)触发时从新渲染组件,由于状态被更新。以这种方式由 React 控制其值的输入表单元素称为受控组件

问题 10:如何 React.createElement ?

主题: React

难度: ⭐⭐⭐

问题:

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
)
复制代码

上述代码如何使用 React.createElement 来实现:

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);
复制代码

问题 11:讲讲什么是 JSX ?

主题: React

难度: ⭐⭐⭐

Facebook 第一次发布 React 时,他们还引入了一种新的 JS 方言 JSX,将原始 HTML 模板嵌入到 JS 代码中。JSX 代码自己不能被浏览器读取,必须使用Babelwebpack等工具将其转换为传统的JS。不少开发人员就能无心识使用 JSX,由于它已经与 React 结合在一直了。

class MyComponent extends React.Component {
  render() {
    let props = this.props;  
    return (
      <div className="my-component">
      <a href={props.url}>{props.name}</a>
      </div>
    );
  }
}
复制代码

问题 12:根据下面定义的代码,能够找出存在的两个问题吗 ?

主题: React

难度: ⭐⭐⭐

请看下面的代码:

答案:

1.在构造函数没有将 props 传递给 super,它应该包括如下行

constructor(props) {
  super(props);
  // ...
}
复制代码

2.事件监听器(经过addEventListener()分配时)的做用域不正确,由于 ES6 不提供自动绑定。所以,开发人员能够在构造函数中从新分配clickHandler来包含正确的绑定:

constructor(props) {
  super(props);
  this.clickHandler = this.clickHandler.bind(this);
  // ...
}
复制代码

问题 13:为何不直接更新 state 呢 ?

主题: React

难度: ⭐⭐⭐

若是试图直接更新 state ,则不会从新渲染组件。

// 错误
 This.state.message = 'Hello world';
复制代码

须要使用setState()方法来更新 state。它调度对组件state对象的更新。当state改变时,组件经过从新渲染来响应:

// 正确作法
This.setState({message: ‘Hello World’});
复制代码

问题 14:React 组件生命周期有哪些不一样阶段?

主题: React

难度: ⭐⭐⭐

在组件生命周期中有四个不一样的阶段:

  1. Initialization:在这个阶段,组件准备设置初始化状态和默认属性。

  2. Mounting:react 组件已经准备好挂载到浏览器 DOM 中。这个阶段包括componentWillMountcomponentDidMount生命周期方法。

  3. Updating:在这个阶段,组件以两种方式更新,发送新的 props 和 state 状态。此阶段包括shouldComponentUpdatecomponentWillUpdatecomponentDidUpdate生命周期方法。

  4. Unmounting:在这个阶段,组件已经再也不被须要了,它从浏览器 DOM 中卸载下来。这个阶段包含 componentWillUnmount 生命周期方法。

除以上四个经常使用生命周期外,还有一个错误处理的阶段:

Error Handling:在这个阶段,不论在渲染的过程当中,仍是在生命周期方法中或是在任何子组件的构造函数中发生错误,该组件都会被调用。这个阶段包含了 componentDidCatch 生命周期方法。

问题 15:React 的生命周期方法有哪些?

主题: React

难度: ⭐⭐⭐

  • componentWillMount:在渲染以前执行,用于根组件中的 App 级配置。

  • componentDidMount:在第一次渲染以后执行,能够在这里作AJAX请求,DOM 的操做或状态更新以及设置事件监听器。

  • componentWillReceiveProps:在初始化render的时候不会执行,它会在组件接受到新的状态(Props)时被触发,通常用于父组件状态更新时子组件的从新渲染

  • shouldComponentUpdate:肯定是否更新组件。默认状况下,它返回true。若是肯定在 stateprops 更新后组件不须要在从新渲染,则能够返回false,这是一个提升性能的方法。

  • componentWillUpdate:在shouldComponentUpdate返回 true 肯定要更新组件以前件以前执行。

  • componentDidUpdate:它主要用于更新DOM以响应propsstate更改。

  • componentWillUnmount:它用于取消任何的网络请求,或删除与组件关联的全部事件监听器。

问题 16:这三个点(...)在 React 干吗用的?

主题: React

难度: ⭐⭐⭐

... 在React(使用JSX)代码中作什么?它叫什么?

<Modal {...this.props} title='Modal heading'  animation={false}/>
复制代码

这个叫扩展操做符号或者展开操做符,例如,若是this.props包含a:1b:2,则

<Modal {...this.props} title='Modal heading' animation={false}>
复制代码

等价于下面内容:

<Modal a={this.props.a} b={this.props.b} title='Modal heading' animation={false}>
复制代码

扩展符号不只适用于该用例,并且对于建立具备现有对象的大多数(或所有)属性的新对象很是方便,在更新state 我们就常常这么作:

this.setState(prevState => {
    return {foo: {...prevState.foo, a: "updated"}};
});
复制代码

问题 17:使用 React Hooks 好处是啥?

主题: React

难度: ⭐⭐⭐

首先,Hooks 一般支持提取和重用跨多个组件通用的有状态逻辑,而无需承担高阶组件或渲染 props 的负担。Hooks 能够轻松地操做函数组件的状态,而不须要将它们转换为类组件。

Hooks 在类中不起做用,经过使用它们,我们能够彻底避免使用生命周期方法,例如 componentDidMountcomponentDidUpdatecomponentWillUnmount。相反,使用像useEffect这样的内置钩子。

问题 18:什么是 React Hooks?

主题: React

难度: ⭐⭐⭐

Hooks是 React 16.8 中的新添加内容。它们容许在不编写类的状况下使用state和其余 React 特性。使用 Hooks,能够从组件中提取有状态逻辑,这样就能够独立地测试和重用它。Hooks 容许我们在不改变组件层次结构的状况下重用有状态逻辑,这样在许多组件之间或与社区共享 Hooks 变得很容易。

问题 19:React 中的 useState() 是什么?

主题: React

难度: ⭐⭐⭐

下面说明useState(0)的用途:

...
const [count, setCounter] = useState(0);
const [moreStuff, setMoreStuff] = useState(...);
...

const setCount = () => {
    setCounter(count + 1);
    setMoreStuff(...);
    ...
};
复制代码

useState 是一个内置的 React Hook。useState(0) 返回一个元组,其中第一个参数count是计数器的当前状态,setCounter 提供更新计数器状态的方法。

我们能够在任何地方使用setCounter方法更新计数状态-在这种状况下,我们在setCount函数内部使用它能够作更多的事情,使用 Hooks,可以使我们的代码保持更多功能,还能够避免过多使用基于类的组件。

问题 20:React 中的StrictMode(严格模式)是什么??

主题: React

难度: ⭐⭐⭐

React 的StrictMode是一种辅助组件,能够帮助我们编写更好的 react 组件,可使用<StrictMode />包装一组组件,而且能够帮我们如下检查:

  • 验证内部组件是否遵循某些推荐作法,若是没有,会在控制台给出警告。

  • 验证是否使用的已经废弃的方法,若是有,会在控制台给出警告。

  • 经过识别潜在的风险预防一些反作用。

问题 21:为何类方法须要绑定到类实例?

主题: React

难度: ⭐⭐⭐

在 JS 中,this 值会根据当前上下文变化。在 React 类组件方法中,开发人员一般但愿 this 引用组件的当前实例,所以有必要将这些方法绑定到实例。一般这是在构造函数中完成的:

class SubmitButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isFormSubmitted: false
    };
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit() {
    this.setState({
      isFormSubmitted: true
    });
  }

  render() {
    return (
      <button onClick={this.handleSubmit}>Submit</button>
    )
  }
}
复制代码

问题 22:什么是 prop drilling,如何避免?

主题: React

难度: ⭐⭐⭐

在构建 React 应用程序时,在多层嵌套组件来使用另外一个嵌套组件提供的数据。最简单的方法是将一个 prop 从每一个组件一层层的传递下去,从源组件传递到深层嵌套组件,这叫作prop drilling

prop drilling的主要缺点是本来不须要数据的组件变得没必要要地复杂,而且难以维护。

为了不prop drilling,一种经常使用的方法是使用React Context。经过定义提供数据的Provider组件,并容许嵌套的组件经过Consumer组件或useContext Hook 使用上下文数据。

问题 23:描述 Flux 与 MVC?

主题: React

难度: ⭐⭐⭐

传统的 MVC 模式在分离数据(Model)、UI(View和逻辑(Controller)方面工做得很好,可是 MVC 架构常常遇到两个主要问题:

数据流不够清晰:跨视图发生的级联更新经常会致使混乱的事件网络,难于调试。

缺少数据完整性:模型数据能够在任何地方发生突变,从而在整个UI中产生不可预测的结果。

使用 Flux 模式的复杂用户界面再也不遭受级联更新,任何给定的React 组件都可以根据 store 提供的数据重建其状态。Flux 模式还经过限制对共享数据的直接访问来增强数据完整性。

问题 24:受控组件和非受控组件区别是啥?

主题: React

难度: ⭐⭐⭐

  • 受控组件是 React 控制中的组件,而且是表单数据真实的惟一来源。
  • 非受控组件是由 DOM 处理表单数据的地方,而不是在 React 组件中。

尽管非受控组件一般更易于实现,由于只需使用refs便可从 DOM 中获取值,但一般建议优先选择受控制的组件,而不是非受控制的组件。

这样作的主要缘由是受控组件支持即时字段验证,容许有条件地禁用/启用按钮,强制输入格式。

问题 25:这段代码有什么问题吗?

主题: React

难度: ⭐⭐⭐⭐

这段代码有什么问题:

this.setState((prevState, props) => {
  return {
    streak: prevState.streak + props.count
  }
})
复制代码

答案:

没有什么问题。这种方式不多被使用,我们能够将一个函数传递给setState,该函数接收上一个 state 的值和当前的props,并返回一个新的状态,若是我们须要根据之前的状态从新设置状态,推荐使用这种方式。

问题 26:什么是 React Context?

主题: React

难度: ⭐⭐⭐⭐

Context 经过组件树提供了一个传递数据的方法,从而避免了在每个层级手动的传递 props 属性。

问题 27:什么是 React Fiber?

主题: React

难度: ⭐⭐⭐⭐

Fiber 是 React 16 中新的协调引擎或从新实现核心算法。它的主要目标是支持虚拟DOM的增量渲染。React Fiber 的目标是提升其在动画、布局、手势、暂停、停止或重用等方面的适用性,并为不一样类型的更新分配优先级,以及新的并发原语。

React Fiber 的目标是加强其在动画、布局和手势等领域的适用性。它的主要特性是增量渲染:可以将渲染工做分割成块,并将其分散到多个帧中。

问题 28:如何在 ReactJS 的 Props上应用验证?

主题: React

难度: ⭐⭐⭐⭐

当应用程序在开发模式下运行时,React 将自动检查我们在组件上设置的全部 props,以确保它们具备正确的数据类型。对于不正确的类型,开发模式下会在控制台中生成警告消息,而在生产模式中因为性能影响而禁用它。强制的 propsisRequired定义的。

下面是一组预约义的 prop 类型:

  • React.PropTypes.string
  • React.PropTypes.number
  • React.PropTypes.func
  • React.PropTypes.node
  • React.PropTypes.bool

例如,我们为用户组件定义了以下的propTypes

import PropTypes from 'prop-types';

class User extends React.Component {
  render() {
    return (
      <h1>Welcome, {this.props.name}</h1>
      <h2>Age, {this.props.age}
    );
  }
}

User.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number.isRequired
};
复制代码

问题 29:在 React 中使用构造函数和 getInitialState 有什么区别?

主题: React

难度: ⭐⭐⭐⭐

构造函数和getInitialState之间的区别就是ES6ES5自己的区别。在使用ES6类时,应该在构造函数中初始化state,并在使用React.createClass时定义getInitialState方法。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { /* initial state */ };
  }
}
复制代码

等价于:

var MyComponent = React.createClass({
  getInitialState() {
    return { /* initial state */ };
  },
});
复制代码

问题 30:如何有条件地向 React 组件添加属性?

主题: React

难度: ⭐⭐⭐⭐

对于某些属性,React 很是聪明,若是传递给它的值是虚值,能够省略该属性。例如:

var InputComponent = React.createClass({
    render: function() {
      var required = true;
      var disabled = false;

      return (
        <input type="text" disabled={disabled} required={required} />
      );
    }
});
复制代码

渲染结果:

<input type="text" required>
复制代码

另外一种可能的方法是:

var condition = true;

var component = (
  <div
    value="foo"
    { ...( condition && { disabled: true } ) } />
);
复制代码

问题 31:Hooks会取代 render props 和高阶组件吗?

主题: React

难度: ⭐⭐⭐⭐

一般,render props和高阶组件仅渲染一个子组件。React团队认为,Hooks 是服务此用例的更简单方法。

这两种模式仍然有一席之地(例如,一个虚拟的 scroller 组件可能有一个 renderItem prop,或者一个可视化的容器组件可能有它本身的 DOM 结构)。但在大多数状况下,Hooks 就足够了,能够帮助减小树中的嵌套。

问题 32:如何避免组件的从新渲染?

主题: React

难度: ⭐⭐⭐⭐

React 中最多见的问题之一是组件没必要要地从新渲染。React 提供了两个方法,在这些状况下很是有用:

  • React.memo():这能够防止没必要要地从新渲染函数组件

  • PureComponent:这能够防止没必要要地从新渲染类组件

这两种方法都依赖于对传递给组件的props的浅比较,若是 props 没有改变,那么组件将不会从新渲染。虽然这两种工具都很是有用,可是浅比较会带来额外的性能损失,所以若是使用不当,这两种方法都会对性能产生负面影响。

经过使用 React Profiler,能够在使用这些方法先后对性能进行测量,从而确保经过进行给定的更改来实际改进性能。

问题 33:什么是纯函数?

主题: React

难度: ⭐⭐⭐⭐⭐

纯函数是不依赖而且不会在其做用域以外修改变量状态的函数。本质上,纯函数始终在给定相同参数的状况下返回相同结果。

问题 34:当调用setState时,React render 是如何工做的?

主题: React

难度: ⭐⭐⭐⭐⭐

我们能够将"render"分为两个步骤:

  1. 虚拟 DOM 渲染:当render方法被调用时,它返回一个新的组件的虚拟 DOM 结构。当调用setState()时,render会被再次调用,由于默认状况下shouldComponentUpdate老是返回true,因此默认状况下 React 是没有优化的。

  2. 原生 DOM 渲染:React 只会在虚拟DOM中修改真实DOM节点,并且修改的次数很是少——这是很棒的React特性,它优化了真实DOM的变化,使React变得更快。

问题 35:如何避免在React从新绑定实例?

主题: React

难度: ⭐⭐⭐⭐⭐

有几种经常使用方法能够避免在 React 中绑定方法:

1.将事件处理程序定义为内联箭头函数

class SubmitButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isFormSubmitted: false
    };
  }

  render() {
    return (
      <button onClick={() => {
        this.setState({ isFormSubmitted: true });
      }}>Submit</button>
    )
  }
}
复制代码

2.使用箭头函数来定义方法:

class SubmitButton extends React.Component {
  state = {
    isFormSubmitted: false
  }

  handleSubmit = () => {
    this.setState({
      isFormSubmitted: true
    });
  }

  render() {
    return (
      <button onClick={this.handleSubmit}>Submit</button>
    )
  }
}
复制代码

3.使用带有 Hooks 的函数组件

const SubmitButton = () => {
  const [isFormSubmitted, setIsFormSubmitted] = useState(false);

  return (
    <button onClick={() => {
        setIsFormSubmitted(true);
    }}>Submit</button>
  )
};
复制代码

代码部署后可能存在的BUG无法实时知道,过后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给你们推荐一个好用的BUG监控工具 Fundebug

原文:www.gangboard.com/blog/reactj…

交流(欢迎加入群,群工做日都会发红包,互动讨论技术)

阿里云最近在作活动,低至2折,有兴趣能够看看:promotion.aliyun.com/ntms/yunpar…

干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。

github.com/qq449245884…

由于篇幅的限制,今天的分享只到这里。若是你们想了解更多的内容的话,能够去扫一扫每篇文章最下面的二维码,而后关注我们的微信公众号,了解更多的资讯和有价值的内容。

clipboard.png

每次整理文章,通常都到2点才睡觉,一周4次左右,挺苦的,还望支持,给点鼓励

相关文章
相关标签/搜索