React高频面试题(附答案)

本文详细解析React中的关键概念,包括组件的this.state和setState的区别,Hooks的优势与限制,Fragment的用途,props验证,数据持久化策略,getDefaultProps的作用,Redux与全局变量的不同,高阶组件的原理,Redux的状态传递,render阶段访问refs的注意事项,性能优化策略,props.children与React.Children的差异,以及React设计理念和最佳实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在 ReactNative中,如何解决8081端口号被占用而提示无法访问的问题?
在运行 react-native start时添加参数port 8082;在 package.json中修改“scripts”中的参数,添加端口号;修改项目下的 node_modules \react-native\local- cli\server\server.js文件配置中的 default端口值。

在React中组件的this.state和setState有什么区别?

this.state通常是用来初始化state的,this.setState是用来修改state值的。如果初始化了state之后再使用this.state,之前的state会被覆盖掉,如果使用this.setState,只会替换掉相应的state值。所以,如果想要修改state的值,就需要使用setState,而不能直接修改state,直接修改state之后页面是不会更新的。
前端react面试题详细解答

hooks 和 class 比较的优势?

一、更容易复用代码

二、清爽的代码风格+代码量更少

缺点

状态不同步
不好用的useEffect,

React Hook 的使用限制有哪些?

React Hooks 的限制主要有两条:

  • 不要在循环、条件或嵌套函数中调用 Hook;
  • 在 React 的函数组件中调用 Hook。

那为什么会有这样的限制呢?Hooks 的设计初衷是为了改进 React 组件的开发模式。在旧有的开发模式下遇到了三个问题。

  • 组件之间难以复用状态逻辑。过去常见的解决方案是高阶组件、render props 及状态管理框架。
  • 复杂的组件变得难以理解。生命周期函数与业务逻辑耦合太深,导致关联部分难以拆分。
  • 人和机器都很容易混淆类。常见的有 this 的问题,但在 React 团队中还有类难以优化的问题,希望在编译优化层面做出一些改进。

这三个问题在一定程度上阻碍了 React 的后续发展,所以为了解决这三个问题,Hooks 基于函数组件开始设计。然而第三个问题决定了 Hooks 只支持函数组件。

那为什么不要在循环、条件或嵌套函数中调用 Hook 呢?因为 Hooks 的设计是基于数组实现。在调用时按顺序加入数组中,如果使用循环、条件或嵌套函数很有可能导致数组取值错位,执行错误的 Hook。当然,实质上 React 的源码里不是数组,是链表。

这些限制会在编码上造成一定程度的心智负担,新手可能会写错,为了避免这样的情况,可以引入 ESLint 的 Hooks 检查插件进行预防。

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

在React中,组件返回的元素只能有一个根元素。为了不添加多余的DOM节点,我们可以使用Fragment标签来包裹所有的元素,Fragment标签不会渲染出任何元素。React官方对Fragment的解释:

React 中的一个常见模式是一个组件返回多个元素。Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点。

import React, {
   
    Component, Fragment } from 'react'

// 一般形式
render() {
   
   
  return (
    <React.Fragment>
      <ChildA />
      <ChildB />
      <ChildC />
    </React.Fragment>
  );
}
// 也可以写成以下形式
render() {
   
   
  return (
    <>
      <ChildA />
      <ChildB />
      <ChildC />
    </>
  );
}
复制代码

React中怎么检验props?验证props的目的是什么?

React为我们提供了PropTypes以供验证使用。当我们向Props传入的数据无效(向Props传入的数据类型和验证的数据类型不符)就会在控制台发出警告信息。它可以避免随着应用越来越复杂从而出现的问题。并且,它还可以让程序变得更易读。

import PropTypes from 'prop-types';

class Greeting extends React.Component {
   
   
  render() {
   
   
    return (
      <h1>Hello, {
   
   this.props.name}</h1>
    );
  }
}

Greeting.propTypes = {
   
   
  name: PropTypes.string
};
复制代码

当然,如果项目汇中使用了TypeScript,那么就可以不用PropTypes来校验,而使用TypeScript定义接口来校验props。

在React中页面重新加载时怎样保留数据?

这个问题就设计到了数据持久化, 主要的实现方式有以下几种:

  • Redux: 将页面的数据存储在redux中,在重新加载页面时,获取Redux中的数据;
  • data.js: 使用webpack构建的项目,可以建一个文件,data.js,将数据保存data.js中,跳转页面后获取;
  • sessionStorge: 在进入选择地址页面之前,componentWillUnMount的时候,将数据存储到sessionStorage中,每次进入页面判断sessionStorage中有没有存储的那个值,有,则读取渲染数据;没有,则说明数据是初始化的状态。返回或进入除了选择地址以外的页面,清掉存储的sessionStorage,保证下次进入是初始化的数据
  • history API: History API 的 pushState 函数可以给历史记录关联一个任意的可序列化 state,所以可以在路由 push 的时候将当前页面的一些信息存到 state 中,下次返回到这个页面的时候就能从 state 里面取出离开前的数据重新渲染。react-router 直接可以支持。这个方法适合一些需要临时存储的场景。

React中有使用过getDefaultProps吗?它有什么作用?

通过实现组件的getDefaultProps,对属性设置默认值(ES5的写法):

var ShowTitle = React.createClass({
   
   
  getDefaultProps:function(){
   
   
    return{
   
   
      title : "React"
    }
  },
  render : function(){
   
   
    return <h1>{
   
   this.props.title}</h1>
  }
});
复制代码

Redux 状态管理器和变量挂载到 window 中有什么区别

两者都是存储数据以供后期使用。但是Redux状态更改可回溯——Time travel,数据多了的时候可以很清晰的知道改动在哪里发生,完整的提供了一套状态管理模式。

随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态)。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。

管理不断变化的 state 非常困难。如果一个 model 的变化会引起另一个 model 变化,那么当 view 变化时,就可能引起对应 model 以及另一个model 的变化,依次地,可能会引起另一个 view 的变化。直至你搞不清楚到底发生了什么。state 在什么时候,由于什么原因,如何变化已然不受控制。 当系统变得错综复杂的时候,想重现问题或者添加新功能就会变得举步维艰。
如果这还不够糟糕,考虑一些来自前端开发领域的新需求,如更新调优、服务端渲染、路由跳转前请求数据等等。前端开发者正在经受前所未有的复杂性,难道就这么放弃了吗?当然不是。

这里的复杂性很大程度上来自于:我们总是将两个难以理清的概念混淆在一起:变化和异步。 可以称它们为曼妥思和可乐。如果把二者分开,能做的很好,但混到一起,就变得一团糟。一些库如 React 视图在视图层禁止异步和直接操作 DOM来解决这个问题。美中不足的是,React 依旧把处理 state 中数据的问题留给了你。Redux就是为了帮你解决这个问题。

React 高阶组件是什么,和普通组件有什么区别,适用什么场景

官方解释∶

高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。

高阶组件(HOC)就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件,它只是一种组件的设计模式,这种设计模式是由react自身的组合性质必然产生的。我们将它们称为纯组件,因为它们可以接受任何动态提供的子组件,但它们不会修改或复制其输入组件中的任何行为。

// hoc的定义
function withSubscription(WrappedComponent, selectData) {
   
   
  return class extends React.Component {
   
   
    constructor(props) {
   
   
      super(props);
      this.state = {
   
   
        data: selectData(DataSource, props)
      
### React 高频面试题答案解析 #### 1. React Fiber 是什么?它的核心概念有哪些? React Fiber 是 React 16 引入的核心架构,旨在提高渲染性能和用户体验。其主要特性是将渲染任务拆分为可中断的单元,使得 React 能够在执行渲染任务时根据优先级进行中断和恢复。核心概念包括: - **Fiber 节点**:每个组件在 Fiber 架构中都有一个对应的 Fiber 节点,用于存储组件的状态、DOM 信息以及其他元数据。 - **工作循环**:通过调度器将任务分片执行,使得渲染过程可以分阶段完成。 - **优先级**:支持任务的中断和恢复,高优先级任务可以抢占低优先级任务的执行权[^1]。 #### 2. React 如何实现跨平台开发? React 可以通过不同的渲染器实现跨平台开发。例如: - **服务器端渲染**:使用 Node.js 进行服务器端渲染,生成 HTML 内容返回给客户端。 - **移动应用开发**:使用 React Native 开发原生移动应用,React 组件可以映射为 Android 或 iOS 的原生控件。 - **多平台支持**:React 的设计允许开发者根据目标平台选择合适的渲染器,从而实现 Web DOM、Android 控件或 iOS 控件的输出[^2]。 #### 3. React 中的 `key` 是什么作用?为什么需要它? `key` 是 React 中用于标识列表中每个元素的唯一标识符。它的主要作用是帮助 React 识别哪些元素发生了变化、被添加或删除,从而提高渲染效率。`key` 应该是稳定的、唯一的,并且通常使用数据中的唯一标识符(如 ID)作为 `key` 的值。如果 `key` 不唯一或不正确,React 可能无法正确更新 DOM,导致性能问题或状态丢失[^2]。 #### 4. React 的单向数据流是什么?如何实现父子组件通信? React 的单向数据流是指数据从父组件流向子组件,子组件不能直接修改父组件传递过来的数据。这种设计确保了数据的一致性和可预测性。父组件通过 `props` 向子组件传递数据,子组件可以通过调用父组件传递的回调函数来触发父组件的状态更新,从而实现双向通信[^3]。 #### 5. React 中的 Context API 是什么?如何使用? Context API 是 React 提供的一种跨层级组件通信的方式,避免了在每一层组件中手动传递 `props`。通过 `React.createContext` 创建一个上下文对象,并使用 `Provider` 组件提供值,子组件可以通过 `useContext` Hook 或 `Consumer` 组件来访问上下文中的值。例如: ```javascript const ThemeContext = React.createContext('light'); function App() { return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); } function Toolbar() { const theme = useContext(ThemeContext); return <div>{theme}</div>; } ``` 上述代码展示了如何创建和使用一个主题上下文[^4]。 #### 6. 高阶组件(HOC)与 Render Props 的区别是什么? - **高阶组件(HOC)**:是一个函数,接受一个组件并返回一个新的组件。HOC 主要用于复用组件逻辑,例如添加状态或生命周期方法。例如: ```javascript function withTheme(Component) { return function WrappedComponent(props) { const theme = useContext(ThemeContext); return <Component {...props} theme={theme} />; }; } ``` - **Render Props**:是一种技术,通过 `props` 中的函数来传递子组件需要的数据。例如: ```javascript class DataProvider extends React.Component { state = { data: 'some data' }; render() { return this.props.render(this.state.data); } } <DataProvider render={(data) => <MyComponent data={data} />} />; ``` Render Props 提供了更灵活的组件组合方式,但可能会导致嵌套过深的问题[^4]。 #### 7. React 中的生命周期方法有哪些?它们的作用是什么? React 组件的生命周期可以分为三个阶段: - **挂载阶段(Mounting)**: - `constructor()`:初始化状态和绑定方法。 - `static getDerivedStateFromProps()`:根据 props 更新 state。 - `render()`:渲染组件。 - `componentDidMount()`:组件挂载后执行,通常用于发起网络请求或初始化第三方库。 - **更新阶段(Updating)**: - `static getDerivedStateFromProps()`:根据新的 props 更新 state。 - `shouldComponentUpdate()`:决定组件是否需要重新渲染。 - `render()`:重新渲染组件。 - `getSnapshotBeforeUpdate()`:获取更新前的 DOM 快照。 - `componentDidUpdate()`:组件更新后执行,通常用于处理 DOM 操作或网络请求。 - **卸载阶段(Unmounting)**: - `componentWillUnmount()`:组件卸载前执行,通常用于清理定时器或取消订阅事件。 #### 8. React 中的 Hook 是什么?常用的 Hook 有哪些? Hook 是 React 16.8 引入的新特性,允许在函数组件中使用状态和其他 React 特性。常用的 Hook 包括: - `useState()`:用于管理组件的状态。 - `useEffect()`:用于处理副作用,如数据获取、订阅或手动 DOM 操作。 - `useContext()`:用于访问上下文中的值。 - `useReducer()`:用于管理复杂的状态逻辑,类似于 Redux 的 reducer 模式。 - `useCallback()`:用于缓存函数,避免不必要的重新渲染。 - `useMemo()`:用于缓存计算结果,避免重复计算。 #### 9. React 中的虚拟 DOM 是什么?它的工作原理是什么? 虚拟 DOM 是 React 用于优化 DOM 操作的一种机制。它是一个轻量的 JavaScript 对象,与实际的 DOM 结构相对应。当组件的状态发生变化时,React 会首先更新虚拟 DOM,然后通过 Diffing 算法比较虚拟 DOM 和实际 DOM 的差异,最后只更新实际 DOM 中发生变化的部分,从而减少不必要的 DOM 操作,提高性能。 #### 10. React 中的性能优化技巧有哪些? - **使用 `React.memo`**:对函数组件进行浅比较,避免不必要的重新渲染。 - **使用 `useCallback` 和 `useMemo`**:缓存函数和计算结果,减少重复创建和计算。 - **代码分割**:使用 `React.lazy` 和 `Suspense` 实现按需加载组件。 - **避免不必要的状态更新**:确保状态更新只在必要时触发。 - **使用生产环境构建**:确保在生产环境中使用优化后的 React 构建版本。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值