面试 React 框架八股文十问十答第四期

作者:程序员小白条,个人博客

相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新!

⭐点赞⭐收藏⭐不迷路!⭐

1)哪些方法会触发 React 重新渲染?重新渲染 render 会做些什么?

React 中的重新渲染可以由以下几种情况触发:

  • 状态变化(State Changes): 当组件的状态(state)发生变化时,render 方法会被调用,导致组件重新渲染。
  • 属性变化(Props Changes): 当组件的属性(props)发生变化时,同样会触发重新渲染。
  • 强制重新渲染(Force Update): 可以使用 forceUpdate 方法来强制触发重新渲染,但一般情况下应该避免使用这个方法。

在重新渲染时,React 会执行以下步骤:

  • 调用 render 方法: React 调用组件的 render 方法生成虚拟 DOM。
  • 比较虚拟 DOM: React 使用虚拟 DOM 的比较算法确定实际 DOM 的变化。
  • 应用变化: 如果有变化,React 会更新实际 DOM 以反映变化。

2)React 如何判断什么时候重新渲染组件?

React 使用一种称为“协调(Reconciliation)”的算法来判断何时重新渲染组件。当组件的状态或属性发生变化时,React 会触发协调过程。在协调过程中,React 会比较前后两次渲染的虚拟 DOM 树,找出变化的部分,然后更新实际的 DOM。

React 使用一些优化策略,如虚拟 DOM 的差异比较和“键”(key)的使用,以提高性能。这样,React 能够最小化实际 DOM 的更新,只更新发生变化的部分。

3)React 声明组件有哪几种方法,有什么不同?

在 React 中,有两种主要声明组件的方式:

  • 类组件(Class Components): 使用 ES6 的类语法来声明组件,继承自 React.Component。类组件具有状态(state)和生命周期方法,适用于复杂的组件逻辑。

    示例:

    class MyClassComponent extends React.Component {render() {return Hello, World!;}}
  • 函数组件(Functional Components): 使用函数来声明组件,通常用于简单的无状态组件。函数组件在 React 16.8 版本引入了钩子(Hooks),使其具备了处理状态和生命周期的能力。

    示例:

    function MyFunctionalComponent() {return Hello, World!;}

4)对有状态组件和无状态组件的理解及使用场景

  • 有状态组件: 有状态组件是指继承自 React.Component 的类组件,具有内部状态(state)和生命周期方法。适用于需要管理复杂状态和生命周期的组件,如处理用户输入、数据获取等。

    示例:

    class MyStatefulComponent extends React.Component {constructor(props) {super(props);this.state = { count: 0 };}render() {return Count: {this.state.count};}}
  • 无状态组件: 无状态组件是指使用函数声明的组件,通常称为函数组件。它没有内部状态,仅依赖于传入的属性(props)。适用于简单的展示型组件,只关注 UI 渲染。

    示例:

    function MyFunctionalComponent(props) {return {props.message};}

选择有状态组件还是无状态组件取决于组件的功能和需求。有状态组件适用于需要管理内部状态和生命周期的情况,而无状态组件则适用于只依赖于传入属性进行渲染的简单组件。

5)对 React 中 Fragment 的理解,它的使用场景是什么?

Fragment(React.Fragment) 是一种特殊的组件,允许在不添加额外节点的情况下组合多个子元素。它在渲染时不会在 DOM 中创建额外的父节点,只是将子元素直接渲染出来。

使用场景包括:

  • 包裹多个元素: 当需要在组件中返回多个子元素,而又不想为它们添加额外的父节点时,可以使用 Fragment。
  • 在列表中使用: 在使用 map 渲染列表时,可以使用 Fragment 包裹每个项,而不会引入额外的 DOM 节点。

示例:

function MyComponent() {return (

Title

Paragraph 1

Paragraph 2

);}

在 React 16.2 版本之前,可以使用空的尖括号 ... 语法作为 Fragment 的简写形式。Fragment 可以帮助开发者更灵活地组织组件结构,而不引入不必要的 DOM 元素。

6)React 如何获取组件对应的 DOM 元素?

在 React 中,可以使用 ref(引用)来获取组件对应的 DOM 元素。ref 是 React 提供的一种访问 DOM 节点或类组件实例的方式。在类组件中,可以通过 React.createRef() 创建一个 ref 对象,并将其赋值给组件的 ref 属性。在函数组件中,可以使用 useRef 钩子来创建 ref。

示例:

class MyComponent extends React.Component {constructor(props) {super(props);this.myRef = React.createRef();}componentDidMount() {// 访问 DOM 元素console.log(this.myRef.current);}render() {return Hello, World!;}}

在上述例子中,this.myRef 将保存对 元素的引用,可以在 componentDidMount 生命周期方法中访问它。

7)React 可以在 render 访问 refs 吗?为什么?

在 React 中,refrender 阶段是可以被访问的。当组件被渲染时,ref 属性会被传递给对应的 DOM 元素或类组件实例。但需要注意的是,访问 ref 得到的是实时的 DOM 或组件实例。

class MyComponent extends React.Component {constructor(props) {super(props);this.myRef = React.createRef();}render() {// 在 render 阶段访问 refconsole.log(this.myRef.current);return Hello, World!;}}

在上述例子中,console.log(this.myRef.current)render 方法中被调用,但此时可能返回的是 null,因为 render 阶段可能早于 DOM 的真实创建。通常,访问 ref 的最佳时机是在 componentDidMount 生命周期方法中,确保在组件已经挂载到 DOM 后再进行操作。

8)对 React 的插槽(Portals)的理解,如何使用,有哪些使用场景

React 的插槽(Portals)是一种将子组件渲染到 DOM 结构中的不同位置的机制。使用 ReactDOM.createPortal(child, container) 方法可以创建一个 portal,将 child 渲染到 container 中。这使得子组件可以脱离父组件的 DOM 层级,而渲染到 DOM 树的其他位置。

使用场景包括:

  • 模态框(Modal): 将模态框组件渲染到 DOM 树的根节点,而不是组件的直接父元素。
  • 全局通知: 在应用中的任何位置渲染通知消息,而不受组件层级的限制。
  • 将组件插入到具有特定样式或层级的 DOM 元素中。

示例:

// PortalComponent.jsimport React from 'react';import ReactDOM from 'react-dom';const PortalComponent = () => {return ReactDOM.createPortal(This is a portal component.,document.getElementById('portal-root') // 插入到指定的 DOM 元素);};export default PortalComponent;// App.jsimport React from 'react';import PortalComponent from './PortalComponent';const App = () => {return (

Main Content

{/* PortalComponent 被渲染到 id 为 "portal-root" 的 DOM 元素中 */});};export default App;

9)在React中如何避免不必要的render?

在 React 中,避免不必要的渲染对性能是至关重要的。以下是一些常见的方法:

  • 使用 PureComponent 或 React.memo: PureComponent 和 React.memo 都可以帮助组件实现浅层的 props 和 state 比较,从而避免不必要的渲染。PureComponent 对于类组件,而 React.memo 对于函数组件。

    // 使用 PureComponentclass MyComponent extends React.PureComponent {// ...}// 或使用 React.memo(适用于函数组件)const MyFunctionalComponent = React.memo((props) => {// ...});
  • 使用 shouldComponentUpdate 钩子: 在类组件中,可以手动实现 shouldComponentUpdate 钩子,根据新旧 props 或 state 的比较结果来决定是否重新渲染。

    class MyComponent extends React.Component {shouldComponentUpdate(nextProps, nextState) {// 根据需要的比较逻辑返回 true 或 falsereturn nextProps.someValue !== this.props.someValue;}// ...}
  • 避免在 render 方法中创建新的对象: 避免在 render 方法中创建新的对象,因为每次渲染都会创建新的引用,可能触发不必要的渲染。

  • 使用 useCallback 和 useMemo: 使用 useCallback 来缓存回调函数,使用 useMemo 来缓存计算结果,以避免它们在每次渲染时都被重新创建。

10)对 React-Intl 的理解,它的工作原理?

React-Intl 是 React 应用中处理国际化(i18n)的库。它基于 Intl API 提供了对日期、时间、数字和消息格式化的支持。

工作原理:

  1. 安装和配置: 首先,需要安装 react-intl 库,并配置提供给应用的本地化数据,如日期格式、货币格式等。
  2. 使用 FormattedMessage 组件: 使用 FormattedMessage 组件来包

开源项目地址:https://gitee.com/falle22222n-leaves/vue_-book-manage-system

已 300 + Star!

⭐点赞⭐收藏⭐不迷路!⭐