《React 面试必知必会》Day5

1,831 阅读4分钟

这是我参与更文挑战的第11天,活动详情查看:更文挑战

大家好,我是 @洛竹

本文首发于 洛竹的官方网站

本文翻译自 sudheerj/reactjs-interview-questions

本文同步于公众号洛竹早茶馆,转载请联系作者。

1. 协调(reconciliation)是什么?

当一个组件的 props 或 state 发生变化时,React 通过比较新返回的元素和之前渲染的元素来决定是否有必要进行实际的 DOM 更新。当它们不相等时,React 将更新 DOM。这个过程被称为 协调(reconciliation)

2. 如何用一个动态键名来设置状态?

如果你使用 ES6 或 Babel 转码器来转换你的 JSX 代码,那么你可以用计算属性命名完成。

handleInputChange(event) {
  this.setState({ [event.target.id]: event.target.value })
}

3. 每次组件渲染时,函数被调用的常见错误是什么?

你需要确保在传递函数作为参数时,没有调用该函数。

render() {
  // 错误❌: handleClick 被调用而不是作为引用被传入
  return <button onClick={this.handleClick()}>{'Click Me'}</button>
}

取而代之的是传递函数本身,不加圆括号。

render() {
  // 正确:handleClick 是作为一个引用传递的!
  return <button onClick={this.handleClick}>{'Click Me'}</button>
}

4. lazy 函数是否支持命名导出?

不,目前 React.lazy 函数只支持默认出口。如果你想导入被命名导出的模块,你可以创建一个中间模块,将其作为默认出口。这也保证了摇树的工作,不会拉取未使用的组件。

让我们来看看一个导出多个命名组件的组件文件。

// 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'));

5. 为什么 React 使用 className 而不是 class 属性?

class 是 JavaScript 的一个关键字,而 JSX 是 JavaScript 的一个扩展。这就是为什么 React 使用 className 而不是 class 的主要原因。传递一个字符串作为 className prop。

render() {
  return <span className={'menu navigation-menu'}>{'Menu'}</span>
}

6. 片段(fragments)是什么?

这是 React 中常见的模式,用于一个组件返回多个元素。片段让你可以对一个 children 的列表进行分组,而无需在 DOM 中添加额外的节点。

render() {
  return (
    <React.Fragment>
      <ChildA />
      <ChildB />
      <ChildC />
    </React.Fragment>
  )
}

这里还有一个短语法可以用,但是很多工具不支持:

render() {
  return (
    <>
      <ChildA />
      <ChildB />
      <ChildC />
    </>
  )
}

7. 为什么片段(fragments)比 div 容器要好?

  1. 片段的速度更快一些,并且由于没有创建额外的 DOM 节点而使用更少的内存。这只有在非常大和深的树上才会体现出真正的好处。
  2. 一些 CSS 机制,如 Flexbox 和 CSS Grid 有一个特殊的父子关系,在中间添加 div 会使其难以保持所需的布局。
  3. DOM 检查器不那么杂乱。

8. 什么是 React 中的传递门(Portal)?

传递门是一种推荐的方式,可以将子节点渲染到父组件的 DOM 层次结构之外的 DOM 节点中。

ReactDOM.createPortal(child, container);

第一个参数是任何可渲染的 React children,比如一个元素、字符串或片段。第二个参数是一个 DOM 元素。

9. 什么是无状态组件?

如果行为是独立于其状态的,那么它可以是一个无状态组件。你可以使用函数或类来创建无状态组件。但除非你需要在你的组件中使用生命周期钩子,否则你应该选择函数组件。如果你决定在这里使用函数组件,会有很多好处;它们易于编写、理解和测试,速度稍快,而且你可以完全避免使用 this 关键字。

10. 什么是状态组件?

如果一个组件的行为依赖于该组件的状态(state),那么它可以被称为有状态的组件。这些有状态的组件总是类组件,并且有一个在构造器(constructor)中被初始化的状态。

class App extends Component {
  // 也可以使用类字段语法
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  render() {
    // ...
  }
}

React 16.8 更新:

Hooks 让你在不写类的情况下使用状态和其他 React 功能。

等效的函数组件

import React, {useState} from 'react';

const App = (props) => {
  const [count, setCount] = useState(0);

  return (
    // JSX
  )
}