react面试题

React是什么?

React是一个开源前端JavaScript库,用于构建可组合的web页面,尤其适用于单页应用程序。
React是由Facebook公司创建的。

React的主要特点是什么?

  • 使用JSX语法
  • 使用虚拟DOM
  • 支持服务端渲染
  • 单向数据流
  • 使用可组合的组件

JSX是什么

JSX代表JavaScript XML,它是ECMAScript的类XML语法扩展。基本上,它只是为React.createElement()函数提供了语法糖,,让我们能够像HTML一样表达JavaScript和模板语法。

元素和组件的区别是什么

Element是一个普通对象,描述您希望在屏幕上展示的内容
Component是创建Element的方式

什么是Pure组件

Pure Component是React中的一个组件类,它与普通组件类(React.Component)飞车类似,唯一的不同是它为你处理了shouldComponentUpdate()方法。当props或state发生变化时,PureComponent会对props和state进行浅比较。而普通组件类则不会默认比较当前props和state与下一个props和state是否相等。因此,普通组件类在shouldComponentUpdate()被调用时默认会重新渲染。在函数组件中,我们可以使用React.memo()API实现类似的功能。

setState()中回调函数的作用

当setState完成并且组件被渲染时调用回调函数。由于setState是异步的,因此回调函数用于任何后期操作。
注意:推荐使用生命周期方法,而不是这个回调函数。

HTML和React中的事件处理有什么不同?

  • HTML中,事件名为全小写,React中为小驼峰。
  • HTML事件为一个函数字符串名称,React中为函数。
  • HTML中可以返回false阻止默认行为,React中只能显式调用preventDefault()

React中的合成事件是什么?

SyntheticEvent合成事件是浏览器本机事件的跨浏览器包装器。它的API与浏览器的本机事件相同,包括stopPropagation()和preventDefault(),只是这些事件在所有浏览器中的工作方式相同。可以使用nativeEvent属性直接从合成事件访问本机事件。

function BookStore() {
  handleTitleChange(e) {
    console.log('The new title is:', e.target.value);
    // 'e' represents synthetic event
    const nativeEvent = e.nativeEvent;
    console.log(nativeEvent);
    e.stopPropogation();
    e.preventDefault();
  }

  return <input name="title" onChange={handleTitleChange} />
}

props中key是什么,在数组中使用它有什么好处?

key是创建元素数组时应包含的特殊字符串属性,key在该数组中应该是唯一的,key帮助React识别哪些项被增删改查。

推荐使用业务id作为key,也可以用数组index作为key(不推荐)。

refs的作用是什么?

ref用于返回对元素的引用。在大多数情况下应该避免使用它们,但是,当您需要直接访问DOM元素或组件实例时,它们会很有用。

在React中,ref是一个用于访问DOM元素或React组件实例的特殊属性。通过使用ref,你可以获取组件或DOM元素的实例并访问其属性或方法。通常情况下,我们使用ref来执行以下操作:

  1. 访问DOM元素或React组件实例的属性或方法。
  2. 在父组件中操作子组件的状态或方法。
  3. 在函数组件中访问组件实例。

下面是一个使用ref的简单示例:

import React, { useRef } from 'react';

function MyComponent() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input type="text" ref={inputRef} />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  );
}

在上面的例子中,我们创建了一个函数组件MyComponent,它包含一个input元素和一个按钮。我们使用useRef钩子创建了一个名为inputRef的ref。当按钮被点击时,我们调用handleClick函数,该函数使用ref访问input元素的实例并聚焦它。

注意,我们将inputRef作为ref属性传递给input元素。这样React就会在组件挂载时自动将input元素的实例赋值给inputRef.current。我们可以在任何时间使用inputRef.current来访问input元素的属性和方法。

什么是转发refs?

Ref 转发是一项功能,它允许某些组件获取它们收到的 ref,并将其进一步传递给子组件。

哪个是更合适的方式在refs和findDOMNode()?

在React中,使用回调函数refs(callback refs)比使用findDOMNode() API更受推荐。因为findDOMNode()会阻止React在未来进行某些改进。

使用findDOMNode()是一种过时的方法,它可以用来访问组件的DOM节点。但是,它会阻止React进行某些优化,例如异步渲染和服务器渲染。而使用回调函数refs可以避免这些问题,因为它们可以在组件挂载时和卸载时分别被调用,不需要通过访问DOM节点来获取组件实例。

因此,在React中,我们推荐使用回调函数refs来访问组件实例,而不是使用findDOMNode() API。

为什么使用string ref是过时的?

在React中,使用字符串类型的refs(String Refs)是一种过时的方法,因为它们在某些情况下会导致一些问题。

使用字符串类型的refs会在组件挂载时创建一个全局变量,该变量的名称与传递给ref属性的字符串值相同。这个全局变量指向组件的实例,从而可以访问该实例的属性和方法。然而,由于这种方法使用全局变量,因此可能会导致冲突或者意外的命名冲突。

另外,使用字符串类型的refs也无法与函数式组件一起使用,因为函数式组件没有实例,而使用字符串类型的refs需要一个组件实例。

因此,尽管在React早期版本中使用字符串类型的refs是一种常见的方法,但现在我们更推荐使用对象类型的refs(Refs with Object)或回调函数类型的refs(Callback Refs)来访问组件实例。这些方法更加稳健,并且可以与函数式组件一起使用。

什么是虚拟DOM?

虚拟 DOM(VDOM)是实际 DOM 的内存表示。它是一种将UI表示保存在内存中并与“真实”DOM同步的方法。这是在调用render函数和元素显示在屏幕上之间发生的一个步骤。这个过程称为调和(reconciliation)。在调和过程中,React会比较虚拟DOM和真实DOM的差异,并仅在需要更新的部分进行DOM操作,从而提高性能和效率。虚拟DOM还可以使React跨平台,因为它可以在Web,移动应用程序和服务器端使用。

虚拟DOM如何工作?

虚拟DOM工作主要包括3个简单的步骤。

  • 当任何底层数据发生变化时,整个UI都会以虚拟DOM表示形式重新呈现。
    react面试题_第1张图片
  • 计算以前的DOM表示和新的DOM表示之间的差异
    react面试题_第2张图片
  • 计算完成后,真实DOM将只更新实际发生变化的内容。
    react面试题_第3张图片

Shadow DOM和虚拟DOM的不同?

Shadow DOM是一种浏览器技术,主要用于在Web组件中限定变量和CSS的作用域。虚拟DOM是JavaScript库在浏览器API之上实现的一个概念。

React Fiber是什么?

Fiber是React v16中的新协调引擎,也是核心算法的重新实现。React Fiber的目标是增加它在动画、布局、手势等领域的适用性,使其能够暂停、中止或重用工作,并为不同类型的更新分配优先级;同时引入新的并发原语。
React Fiber的主要目标是增加其在动画、布局和手势等方面的适用性。它的主要特性是增量渲染:将渲染工作分成多个块并在多个帧中分散执行。

它的主要目标包括:

能够将可中断的工作拆分成块。
能够对正在进行的工作进行优先级、重新基于和重用。
能够在父级和子级之间来回切换以支持React中的布局。
能够从render()中返回多个元素。
更好地支持错误边界。

什么是受控组件?什么是非受控组件?

React中的受控组件是由React组件控制并与React状态同步的表单元素。换句话说,输入表单元素的值由React组件的状态控制,并且当用户输入时,React会更新组件的状态并相应地更新表单元素的值。

相反,非受控组件是由DOM自身控制并不与React状态同步的表单元素。非受控组件的值由DOM中的表单元素本身管理,通常使用refs获取表单元素的值。

在大多数情况下,推荐使用受控组件来实现表单。在受控组件中,表单数据由React组件处理。另一种选择是非受控组件,其中表单数据由DOM本身处理。

createElement 和cloneElement的区别?

JSX元素将被转译为React.createElement()函数,用于创建React元素,这些元素将用于表示UI的对象。而cloneElement则用于克隆一个元素并传递新的props。

React中的提升状态是什么?

当多个组件需要共享相同的可变数据时,建议将共享状态提升到它们最近的共同祖先组件中。这意味着如果两个子组件共享来自其父组件的相同数据,则将状态移动到父组件而不是在两个子组件中都维护本地状态。

React的生命周期?

组件生命周期具有3个不同的生命周期阶段:

  • 挂载阶段
    组件已准备好挂载到浏览器DOM。此阶段包括从constructor(),getDerivedStateFromProps(),render()和componentDidMount()生命周期方法进行初始化。
  • 更新阶段
    在此阶段,组件以2种方法进行更新,即发送props并从setState()或forceUpdate()更新状态。此阶段包括getDerivedStateFromProps(),shouldComponentUpdate(),render(),getSnapshotBeforeUpdate()和componentDidUpdate()生命周期方法。
  • 卸载阶段
    在此最后阶段,组件不在需要并从浏览器DOM中卸载。此阶段包括componentWillUnmount()生命周期方法。

值得一提的是,React在应用更改到DOM时内部有一个阶段的概念。它们分别被分为以下阶段:

  • 渲染阶段
    组件将在没有任何副作用的情况下渲染。
  • 预提交阶段
  • 提交阶段
    React与DOM一起工作,并依次执行最终的生命周期,分别是componentDidMount()用于挂载,componentDidUpdate()用于更新,componentWillUnmount()用于卸载。
    react面试题_第4张图片
    getDerivedStateFromProps:在调用 render() 之前调用,每次渲染都会调用。存在于需要派生状态的罕见用例中。如果需要派生状态,那么值得一读。

componentDidMount:在首次渲染后执行,此处应执行所有 AJAX 请求、DOM 或状态更新和设置事件监听器等操作。

shouldComponentUpdate:确定组件是否会被更新。默认情况下,它返回 true。如果您确定在状态或属性更新后组件不需要重新渲染,则可以返回 false 值。这是一个提高性能的好地方,因为它允许您在组件接收到新 prop 时防止重新渲染。

getSnapshotBeforeUpdate:在呈现的输出提交到 DOM 之前执行。该函数返回的任何值都将传递给 componentDidUpdate()。这对于捕获来自 DOM 的信息(例如滚动位置)非常有用。

componentDidUpdate:主要用于响应 prop 或 state 的更改来更新 DOM。如果 shouldComponentUpdate() 返回 false,则不会触发此方法。

componentWillUnmount:用于取消任何正在进行的网络请求或删除与组件关联的所有事件侦听器。

什么是HOC高阶组件?

高阶组件 (Higher-Order Component, HOC) 是一个接受一个组件并返回一个新组件的函数。基本上,这是从 React 的组合性质中推导出来的模式。

我们称它们为纯组件,因为它们可以接受任何动态提供的子组件,但它们不会修改或复制任何输入组件的行为。

const EnhancedComponent = higherOrderComponent(WrappedComponent);
HOC 可用于许多用例:

代码重用,逻辑和启动抽象。
渲染劫持。
状态抽象和操作。
属性操作。

如何为HOC组件创建props代理?

function HOC(WrappedComponent) {
  return class Test extends Component {
    render() {
      const newProps = {
        title: "New Header",
        footer: false,
        showFeatureX: false,
        showFeatureY: true,
      };

      return <WrappedComponent {...this.props} {...newProps} />;
    }
  };
}

什么是context?

Context提供了一种通过组件树传递数据的方式,而不必在每个层级手动传递props。

什么是子prop?

Children是一个prop(this.props.children),它允许您将组件作为数据传递给其他组件,就像使用其他prop一样。放置在组件的开放标签和结束标签之间的组件树将作为children prop传递给该组件。

React API中有几种可用于处理此prop的方法,包括React.Children.map,React.Children.forEach,React.Children.count,React.Children.only,React.Children.toArray。

const MyDiv = React.createClass({
  render: function () {
    return <div>{this.props.children}</div>;
  },
});

ReactDOM.render(
  <MyDiv>
    <span>{"Hello"}</span>
    <span>{"World"}</span>
  </MyDiv>,
  node
);

React中如何写注释?

React/JSX 中的注释类似于 JavaScript 多行注释,但用大括号括起来。

<div>
  {/* Single-line comments(In vanilla JavaScript, the single-line comments are represented by double slash(//)) */}
  {`Welcome ${user}, let's play React`}
</div>

什么是协调(reconciliation)?

当一个组件的props或者state发生改变时,React会比较新生成的元素和之前渲染的元素,判断是否需要对DOM进行更新。当它们不相等时,React会更新DOM。这个过程被称为协调(reconciliation)。

惰性函数是否支持命名导出?

不支持命名导出。目前,React.lazy 函数仅支持默认导出。如果想要导入命名导出的模块,可以创建一个中间模块,将其重新导出为默认导出。这也可以确保 Tree Shaking 保持工作状态,不会拉取未使用的组件。假设一个组件文件中有多个命名组件:

// MoreComponents.js
export const SomeComponent = /* … /;
export const UnusedComponent = / … */;
可以在中间文件 IntermediateComponent.js 中重新导出 MoreComponents.js 中的组件:

// IntermediateComponent.js
export { SomeComponent as default } from “./MoreComponents.js”;
然后可以使用 lazy 函数导入模块,如下所示:

import React, { lazy } from “react”;
const SomeComponent = lazy(() => import(“./IntermediateComponent.js”))

什么是React的Fragment?

什么是 React 的 Fragment?

Fragments 是 React 的一种特殊语法,用于组合一组子元素并返回它们,而不需要在 DOM 中创建额外的节点。使用 Fragment 可以有效地避免不必要的 HTML 标签的渲染。简单来说,Fragments 就是一种占位符,让组件可以返回多个元素而不需要添加额外的 div 标签或其他容器。在 React 16 版本之前,通常使用数组或自定义组件来实现类似的效果,但这种方法会导致代码变得混乱和难以维护。

下面是一个使用 Fragment 的示例:

import React, { Fragment } from 'react';

function MyComponent() {
  return (
    <Fragment>
      <h1>Title</h1>
      <p>Paragraph 1</p>
      <p>Paragraph 2</p>
    </Fragment>
  );
}

在上面的示例中,Fragment 像是一个占位符,它会被 React 自动忽略,并将内部的子元素直接渲染到组件的根节点中。在 React 16 版本之前,通常需要将子元素用一个数组包裹,或者使用一个无意义的自定义组件来实现相同的效果。

为什么使用Fragments比容器div好?

为什么使用Fragments比容器div好?

以下是原因列表:

Fragments比容器div更快,并且使用更少的内存,因为它们不创建额外的DOM节点。这只在非常大而深的树上才有真正的好处。

一些CSS机制(如Flexbox和CSS Grid)具有特殊的父子关系,添加div使得难以保持所需的布局。

DOM检查器(Inspector)更简洁。

什么是React中的Portal?

Portal 是一种推荐的将子元素渲染到存在于父组件 DOM 层次结构之外的 DOM 节点的方法。

ReactDOM.createPortal(child, container);
第一个参数是可渲染的 React 子元素,例如元素、字符串或 fragment。第二个参数是一个 DOM 元素。

什么是无状态组件?

如果组件的行为与其状态无关,则它可以是无状态组件。

如何在React中对props进行验证

在React中,您可以使用PropTypes库来验证组件的props。PropTypes库是React内置的一部分,您可以使用它来确保组件接收到正确的props类型。下面是一个简单的例子,展示了如何在组件中使用PropTypes:

首先,您需要从PropTypes库导入所需的prop类型。例如,如果您需要验证props是一个字符串类型,您可以这样导入它:

import PropTypes from 'prop-types';

然后,您可以在组件中使用propTypes属性来验证props。例如,下面是一个简单的组件,它期望一个名为“name”的字符串props:

import React from 'react';
import PropTypes from 'prop-types';

function Greeting(props) {
  return <h1>Hello, {props.name}!</h1>;
}

Greeting.propTypes = {
  name: PropTypes.string
};

export default Greeting;

React的主要优点?

使用虚拟DOM提高应用程序的性能:React使用虚拟DOM,它可以最小化DOM操作,从而提高了应用程序的性能。虚拟DOM是在内存中构建的轻量级副本,React通过比较虚拟DOM和实际DOM之间的差异来决定什么需要更新。

JSX使代码易于阅读和编写:JSX是一种将HTML和JavaScript结合在一起的语法,可以使组件代码易于阅读和编写。通过将HTML标记和JavaScript代码结合在一起,React组件的结构更清晰,易于理解和维护。

可在客户端和服务器端(SSR)渲染:React支持服务器端渲染(SSR),这意味着React应用程序可以在服务器端进行渲染,并将HTML发送到客户端,从而提高了应用程序的性能和SEO优化。

与其他框架(如Angular和Backbone)集成简单:React是一个仅提供视图层的库,因此可以与其他框架(如Angular和Backbone)轻松集成,使开发人员可以使用React构建UI组件,同时使用其他框架来管理应用程序的数据和逻辑。

使用Jest等工具编写单元和集成测试简单:React具有良好的测试支持,并提供了广泛的测试工具和框架。使用工具如Jest和Enzyme,开发人员可以轻松地编写单元测试和集成测试,以确保应用程序的质量和稳定性。

React的不足点?

React只是一个视图库,不是一个完整的框架:React只提供UI层的功能,不提供其他框架(如Angular)中的数据绑定、路由和HTTP请求等功能。因此,开发人员需要选择并使用其他库或框架来实现这些功能,这需要一些额外的配置和学习成本。

对于新手来说,有一定的学习曲线:如果你是新手,尤其是没有Web开发经验的开发人员,React的学习曲线可能会比较陡峭。在理解和使用React之前,需要先学习JavaScript、HTML和CSS等基础知识。

集成React到传统MVC框架需要一些额外的配置:将React集成到传统的MVC框架中,需要一些额外的配置和技术知识,这可能会增加一些复杂度。

内联模板和JSX会增加代码复杂性:在React中,可以使用JSX将HTML和JavaScript结合在一起,但这也会增加代码的复杂性,尤其是当你在组件中使用内联模板时。因此,开发人员需要细心地设计和组织组件,以避免代码复杂性过高。

太多的小组件可能会导致过度设计或样板代码:React鼓励将UI拆分成许多小组件,但如果组件数量过多,就可能会导致代码重复和过度设计的问题。因此,需要在组件的设计和组织中找到一个平衡点,以确保代码的简洁性和可维护性。

React中的错误边界是什么?

React v16引入了错误边界(Error Boundaries)的概念,它是一个React组件,可以捕获并处理子组件中抛出的JavaScript错误。

当React组件中发生错误时,通常会导致整个组件树的崩溃,这可能会使用户看到一个空白的页面或错误信息。但是,如果在组件树中添加了错误边界组件,就可以通过它们来处理错误,从而避免整个应用程序崩溃。

错误边界组件可以定义一个或多个错误处理方法,例如componentDidCatch()方法,来处理子组件中的错误。当子组件抛出错误时,错误边界组件就会捕获该错误,并调用定义的错误处理方法。这使得应用程序可以在错误发生后继续运行,并显示一个友好的错误信息,而不是崩溃或显示空白页面。

需要注意的是,错误边界组件只能捕获它们直接包含的子组件的错误,而不能捕获它们自身或其他祖先组件中的错误。因此,在应用程序中添加错误边界组件时,需要考虑到组件树的结构和层次,以确保能够正确地捕获和处理错误。

react-dom包的作用是什么?

主要是render方法,在我们的最外层,需要使用render()函数将react组件绑定到dom中。
这个方法被用来将一个React元素渲染到指定的容器中,并返回组件的引用。如果这个React元素之前已经被渲染到了容器中,它会执行更新操作,只会修改必要的DOM以反应最新的变化。

ReactDOM.render(element, container, [callback])

如果提供了可选的回调函数,它会在组件被渲染或更新之后执行。

ReactDOMServer是什么?

ReactDOMServer对象使您能够将组件呈现为静态标记(通常用于node服务器)。该对象主要用于服务器渲染(SSR)。

如何使用innerHTML在React中?

dangerouslySetInnerHTML 属性是 React 中替代在浏览器 DOM 中使用 innerHTML 的方法。和 innerHTML 一样,使用这个属性存在跨站脚本攻击(XSS)的风险。你只需要传递一个 __html 对象作为键,以及 HTML 文本作为值即可。

在下面的例子中,MyComponent 使用 dangerouslySetInnerHTML 属性来设置 HTML 标记:

function createMarkup() {
  return { __html: "First · Second" };
}

function MyComponent() {
  return <div dangerouslySetInnerHTML={createMarkup()} />;
}

为什么我们需要向setState()传递一个函数?

这是因为setState()是一个异步操作。React出于性能方面的考虑对状态更改进行了批处理,因此在调用setState()之后,状态可能不会立即更改。这意味着您不应该依赖当前状态来调用setState(),因为您无法确定那个状态将是什么。解决方案是向setState()传递一个函数,以前一个状态作为参数。通过这样做,您可以避免由于setState()的异步性质导致用户在访问时获取旧状态值的问题。

假设初始的计数值为零。在三次连续的递增操作之后,该值只会增加一次。

什么是React中的严格模式?

React.StrictMode 是一个有用的组件,可用于突出应用程序中潜在的问题。与 一样, 不会渲染任何额外的 DOM 元素。它会激活其子组件的额外检查和警告。这些检查仅适用于开发模式。

在上面的代码示例中,严格模式检查仅适用于 和 组件。

React.StrictMode 目前可以帮助你:

识别具有不安全生命周期的组件
警告使用遗留的字符串引用 API
警告使用已弃用的 findDOMNode API
检测意外的副作用
检测遗留的 context API。

如何使用https?

"scripts": {
  "start": "set HTTPS=true && react-scripts start"
}

如何避免在create-react-app中使用相对路径导入?

你可以在项目根目录下创建一个名为.env的文件,并写入以下内容:

NODE_PATH=src/app

然后重新启动开发服务器。现在,你就可以在src/app中导入任何东西而无需使用相对路径了。

为什么组件构造函数只会被调用一次?

React的协调算法假设,如果一个自定义组件在后续的渲染中出现在相同的位置,而没有任何相反的信息,那么它与之前的组件是相同的,因此会重用之前的实例而不是创建新的实例。这就是为什么组件构造函数只会被调用一次的原因。

你可能感兴趣的:(react.js,javascript,前端)