前端关于Recat面试题(四)

60.如果在构造函数中使用 setState() 会发生什么?

当你使用 setState() 时,除了设置状态对象之外,React 还会重新渲染组件及其所有的子组件。你会得到这样的错误:Can only update a mounted or mounting component.。因此我们需要在构造函数中使用 this.state 初始化状态。

61.索引作为键的影响是什么?

Keys 应该是稳定的,可预测的和唯一的,这样 React 就能够跟踪元素。

在下面的代码片段中,每个元素的键将基于列表项的顺序,而不是绑定到即将展示的数据上。这将限制 React 能够实现的优化。

{todos.map((todo, index) =>
  <Todo
    {...todo}
    key={index}
  />
)}

假设 todo.id 对此列表是唯一且稳定的,如果将此数据作为唯一键,那么 React 将能够对元素进行重新排序,而无需重新创建它们。

{todos.map((todo) =>
  <Todo {...todo}
    key={todo.id} />
)}

62.如果在初始状态中使用 props 属性会发生什么?

如果在不刷新组件的情况下更改组件上的属性,则不会显示新的属性值,因为构造函数函数永远不会更新组件的当前状态。只有在首次创建组件时才会用 props 属性初始化状态。

以下组件将不显示更新的输入值:

class MyComponent extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      records: [],
      inputValue: this.props.inputValue
    };
  }

  render() {
    return <div>{this.state.inputValue}</div>
  }
}

在 render 方法使用使用 props 将会显示更新的值:

class MyComponent extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      record: []
    }
  }

  render() {
    return <div>{this.props.inputValue}</div>
  }
}

63.为什么在 DOM 元素上展开 props 需要小心?

当我们展开属性时,我们会遇到添加未知 HTML 属性的风险,这是一种不好的做法。相反,我们可以使用属性解构和...rest 运算符,因此它只添加所需的 props 属性。例如,

const ComponentA = () =>
  <ComponentB isDisplay={true} className={'componentStyle'} />

const ComponentB = ({ isDisplay, ...domProps }) =>
  <div {...domProps}>{'ComponentB'}</div>

64.如何 memoize(记忆)组件?

有可用于函数组件的 memoize 库。例如 moize 库可以将组件存储在另一个组件中。(类似Vue的keep-alive组件)

import moize from 'moize'
import Component from './components/Component' // this module exports a non-memoized component

const MemoizedFoo = moize.react(Component)

const Consumer = () => {
  <div>
    {'I will memoize the following entry:'}
    <MemoizedFoo/>
  </div>
}

65.什么是 CRA 及其好处?

create-react-app CLI 工具允许你无需配置步骤,快速创建和运行 React 应用。

让我们使用 CRA 来创建 Todo 应用:

# Installation
$ npm install -g create-react-app

# Create new project
$ create-react-app todo-app
$ cd todo-app

# Build, test and run
$ npm run build
$ npm run test
$ npm start

它包含了构建 React 应用程序所需的一切:

  1. React, JSX, ES6, 和 Flow 语法支持。
  2. ES6 之外的语言附加功能,比如对象扩展运算符。
  3. Autoprefixed CSS,因此你不在需要 -webkit- 或其他前缀。
  4. 一个快速的交互式单元测试运行程序,内置了对覆盖率报告的支持。
  5. 一个实时开发服务器,用于警告常见错误。
  6. 一个构建脚本,用于打包用于生产中包含 hashes 和 sourcemaps 的 JS、CSS 和 Images 文件。

66.在 mounting 阶段生命周期方法的执行顺序是什么?

在创建组件的实例并将其插入到 DOM 中时,将按以下顺序调用生命周期方法。

  1. constructor()
  2. static getDerivedStateFromProps()
  3. render()
  4. componentDidMount()

67.在 React v16 中,哪些生命周期方法将被弃用?

以下生命周期方法将成为不安全的编码实践,并且在异步渲染方面会更有问题。

  1. componentWillMount()
  2. componentWillReceiveProps()
  3. componentWillUpdate()

从 React v16.3 开始,这些方法使用 UNSAFE_ 前缀作为别名,未加前缀的版本将在 React v17 中被移除。

68.生命周期方法 getDerivedStateFromProps() 的目的是什么?

新的静态 getDerivedStateFromProps() 生命周期方法在实例化组件之后以及重新渲染组件之前调用。它可以返回一个对象用于更新状态,或者返回 null 指示新的属性不需要任何状态更新。

class MyComponent extends React.Component {
  static getDerivedStateFromProps(props, state) {
    // ...
  }
}

此生命周期方法与 componentDidUpdate() 一起涵盖了 componentWillReceiveProps() 的所有用例。

69.生命周期方法 getSnapshotBeforeUpdate() 的目的是什么?

新的 getSnapshotBeforeUpdate() 生命周期方法在 DOM 更新之前被调用。此方法的返回值将作为第三个参数传递给componentDidUpdate()

class MyComponent extends React.Component {
  getSnapshotBeforeUpdate(prevProps, prevState) {
    // ...
  }
}

此生命周期方法与 componentDidUpdate() 一起涵盖了 componentWillUpdate() 的所有用例。

70.推荐的组件命名方法是什么?

建议通过引用命名组件,而不是使用 displayName

使用 displayName 命名组件:

export default React.createClass({
  displayName: 'TodoApp',
  // ...
})

推荐的方式:

export default class TodoApp extends React.Component {
  // ...
}

71.在组件类中方法的推荐顺序是什么?

  • 组件创建阶段

static 开头的 只会执行一次

constructor 构造器 只会执行一次

getDerivedStateFromProps: 当子组件接收到新的props会执行,作用:将传递的props映射到state里面 会执行多次

render 构建虚拟dom,但是此时虚拟dom还没有渲染到页面 会执行多次

componentDidMount:组建的虚拟dom已经挂载到页面 只会执行一次

  • 组件运行阶段:根据 props 属性 或 state 状态的改变,有选择性的执行0到多次

getDerivedStateFromProps:组件将要接收到新的props属性

shouldComponentUpdate:组件是否需要被更新,返回值是true或者false。此时可以获取最新的props和state数据

render: 重新更新渲染组件的虚拟dom

getSnapshotBeforeUpdate:在最近一次渲染提交到 DOM 节点之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置),返回值将作为参数传递给componentDidUpdate

componentDidUpdate: 组件完成了更新,此时页面已经是最新的了

  • 组件销毁阶段:只执行一次

componentWillUnmount: 组件将要被销毁,此时组件还可以被使用

72.什么是 switching 组件?

switching 组件是渲染多个组件之一的组件。我们需要使用对象将 prop 映射到组件中。

例如,以下的 switching 组件将基于 page 属性显示不同的页面:

import HomePage from './HomePage'
import AboutPage from './AboutPage'
import ServicesPage from './ServicesPage'
import ContactPage from './ContactPage'

const PAGES = {
  home: HomePage,
  about: AboutPage,
  services: ServicesPage,
  contact: ContactPage
}

const Page = (props) => {
  const Handler = PAGES[props.page] || ContactPage

  return <Handler {...props} />
}

// The keys of the PAGES object can be used in the prop types to catch dev-time errors.
Page.propTypes = {
  page: PropTypes.oneOf(Object.keys(PAGES)).isRequired
}

73.为什么我们需要将函数传递给 setState() 方法?

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

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

// assuming this.state.count === 0
this.setState({ count: this.state.count + 1 })
this.setState({ count: this.state.count + 1 })
this.setState({ count: this.state.count + 1 })
// this.state.count === 1, not 3

如果将函数传递给 setState(),则 count 将正确递增。

this.setState((prevState, props) => ({
  count: prevState.count + props.increment
}))
// this.state.count === 3 as expected

74.你认为状态更新(state)是如何合并的?

当你在组件中调用 setState() 方法时,React 会将提供的对象合并到当前状态。例如,让我们以一个使用帖子和评论详细信息的作为状态变量的 Facebook 用户为例:

  constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }


现在,你可以独立调用 setState() 方法,单独更新状态变量:

 componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments
      });
    });
  }


如上面的代码段所示,this.setState({comments}) 只会更新 comments 变量,而不会修改或替换 posts 变量。

75.在 React 中什么是严格模式?

React.StrictMode 是一个有用的组件,用于突出显示应用程序中的潜在问题。就像 <Fragment><StrictMode> 一样,它们不会渲染任何额外的 DOM 元素。它为其后代激活额外的检查和警告。这些检查仅适用于开发模式。

import React from 'react'

function ExampleApplication() {
  return (
    <div>
      <Header />
      <React.StrictMode>
        <div>
          <ComponentOne />
          <ComponentTwo />
        </div>
      </React.StrictMode>
      <Footer />
    </div>
  )
}

在上面的示例中,strict mode 检查仅应用于 <ComponentOne><ComponentTwo> 组件。

76.React 中支持哪些指针事件?

Pointer Events 提供了处理所有输入事件的统一方法。在过去,我们有一个鼠标和相应的事件监听器来处理它们,但现在我们有许多与鼠标无关的设备,比如带触摸屏的手机或笔。我们需要记住,这些事件只能在支持 Pointer Events 规范的浏览器中工作。

目前以下事件类型在 React DOM 中是可用的:

  1. onPointerDown
  2. onPointerMove
  3. onPointerUp
  4. onPointerCancel
  5. onGotPointerCapture
  6. onLostPointerCaptur
  7. onPointerEnter
  8. onPointerLeave
  9. onPointerOver
  10. onPointerOut

77.在 React v16 中是否支持自定义 DOM 属性?

是的,在过去 React 会忽略未知的 DOM 属性。如果你编写的 JSX 属性 React 无法识别,那么 React 将跳过它。例如:

<div mycustomattribute={'something'} />

在 React 15 中将在 DOM 中渲染一个空的 div:

<div />

在 React 16 中,任何未知的属性都将会在 DOM 显示:

<div mycustomattribute='something' />

这对于应用特定于浏览器的非标准属性,尝试新的 DOM APIs 与集成第三方库来说非常有用。

78.constructor 和 getInitialState 有什么区别?

当使用 ES6 类时,你应该在构造函数中初始化状态,而当你使用 React.createClass() 时,就需要使用 getInitialState() 方法。

使用 ES6 类:

class MyComponent extends React.Component {
  constructor(props) {
    super(props)
    this.state = { /* initial state */ }
  }
}

使用 React.createClass():

const MyComponent = React.createClass({
  getInitialState() {
    return { /* initial state */ }
  }
})

注意: 在 React v16 中 React.createClass() 已被弃用和删除,请改用普通的 JavaScript 类。

79.是否可以在不调用 setState 方法的情况下,强制组件重新渲染?

默认情况下,当组件的状态或属性改变时,组件将重新渲染。如果你的 render() 方法依赖于其他数据,你可以通过调用 forceUpdate() 来告诉 React,当前组件需要重新渲染。

component.forceUpdate(callback)

建议避免使用 forceUpdate(),并且只在 render() 方法中读取 this.propsthis.state

80.在 JSX 中如何进行循环?

你只需使用带有 ES6 箭头函数语法的 Array.prototype.map 即可。例如,items 对象数组将会被映射成一个组件数组:

<tbody>
  {items.map(item => <SomeComponent key={item.id} name={item.name} />)}
</tbody>

你不能使用 for 循环进行迭代:

<tbody>
  for (let i = 0; i < items.length; i++) {
    <SomeComponent key={items[i].id} name={items[i].name} />
  }
</tbody>

这是因为 JSX 不能在JSX表达式中使用语句。

发布了29 篇原创文章 · 获赞 0 · 访问量 741

猜你喜欢

转载自blog.csdn.net/Jojorain/article/details/105521367