React 面试题整理

一、react 和 vue 的区别是什么?

1、vue是响应式的数据双向绑定系统,而react是单向数据流,没有双向绑定。
2、vue的语法较为简单,适用于小型项目创建,而react更适用于Web端和原生App的开发,侧重于大型应用。
3、Templating vs JSX

React和Vue.js之间最大的区别在于模板的实现方式。

4、状态管理与对象属性

react:
如果你熟悉React,你就会知道应用状态是一个关键概念。甚至还有一些专门用于管理大型状态对象的框架,比如Redux。另外,React应用程序中的状态数据是不可变的,这意味着它不能直接更改(尽管这并不完全正确)。在React中,你需要使用setState()方法(或useState()钩子)来修改本地状态中的任何内容。
vue:
对于Vue.js,不需要本地状态对象,数据是通过Vue对象上的data属性管理的。
在Vue中,不需要调用像setState()这样的状态管理函数,因为Vue对象上的data参数充当了应用程序数据的持有者。
在关于大规模应用程序的状态管理的话题上,Vue.js的创建者Evan You说过,这种解决方案适合小规模应用程序,但不能扩展到大型应用程序。
在大多数情况下,框架本身提供的内置状态管理模式对于大型应用程序是不够的,必须使用像Redux或Vuex这样的专用解决方案。

5、Build Tools

在React中,这是Create React App(CRA);
在Vue.js中,它是vue-cli。

6.这两个框架之间的最后一个相似之处(和不同之处)是它们如何处理伴生框架。

React和Vue.js都只关注UI层,而把路由和状态处理等功能留给其他框架。
Vue.js和React之间的区别在于它们如何与各自的配套框架相关联。
Vue.js核心团队维护Vue -router和Vue框架,并将它们置于主Vue之下。
React -router和React -redux由社区成员维护,并不是在Facebook/React的官方保护伞下。

二、虚拟DOM的原理?优点与缺点?

原理:
1.虚拟DOM本质上是JavaScript对象,是对真实DOM的抽象
2.状态变更时,记录新树和旧树的差异
3.最后把差异更新到真正的dom中
优点:

1.保证性能下限: 虚拟DOM可以经过diff找出最小差异,然后批量进行patch,这种操作虽然比不上手动优化,但是比起粗暴的DOM操作性能要好很多,因此虚拟DOM可以保证性能下限
无需手动操作DOM: 虚拟DOM的diff和patch都是在一次更新中自动进行的,我们无需手动操作DOM,极大提高开发效率
2.跨平台: 虚拟DOM本质上是JavaScript对象,而DOM与平台强相关,相比之下虚拟DOM可以进行更方便地跨平台操作,例如服务器渲染、移动端开发等等

缺点:

无法进行极致优化: 在一些性能要求极高的应用中虚拟DOM无法进行针对性的极致优化,比如VScode采用直接手动操作DOM的方式进行极端的性能优化

三、类组件和函数组件之间的区别是?

类组件:可以使用其他特性,如状态 state 和生命周期钩子
函数组件:当组件只是接收 props 渲染到页面时,就是无状态组件,也被称为哑组件或展示组件。

区别:
1.类组件有 this,函数组件没有
2.类组件有生命周期,函数组件没有
3.类组件有状态 state,函数组件没有

函数组件的性能比类组件的性能要高,因为类组件使用的时候要实例化,而函数组件直接执行函数取返回结果即可。为了提高性能,尽量使用函数组件。

四、React 中 refs 是做什么的?

Refs 提供了一种访问在render方法中创建的 DOM 节点或者 React 元素的方法。在典型的数据流中,props 是父子组件交互的唯一方式,想要修改子组件,需要使用新的pros重新渲染它。凡事有例外,某些情况下咱们需要在典型数据流外,强制修改子代,这个时候可以使用 Refs。
咱们可以在组件添加一个 ref 属性来使用,该属性的值是一个回调函数,接收作为其第一个参数的底层 DOM 元素或组件的挂载实例。

class UnControlledForm extends Component {
  handleSubmit = () => {
    console.log("Input Value: ", this.input.value)
  }
  render () {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type='text'
          ref={(input) => this.input = input} />
        <button type='submit'>Submit</button>
      </form>
    )
  }
}

五、state 和 props 区别是什么?

props和state是普通的 JS 对象。虽然它们都包含影响渲染输出的信息,但是它们在组件方面的功能是不同的。即
1.state 是组件自己管理数据,控制自己的状态,可变;
2.props 是外部传入的数据参数,不可变;
3.没有state的叫做无状态组件(函数组件),有state的叫做有状态组件;
4.多用 props,少用 state,也就是多写无状态组件(因为类组件使用的时候要实例化,而函数组件直接执行函数取返回结果即可。为了提高性能,尽量使用函数组件。)。

六、什么是高阶组件?

高阶组件(HOC)是接受一个组件并返回一个新组件的函数。高阶组件不是组件,是增强函数,可以输入一个元组件,返回出一个新的增强组件

const EnhancedComponent = higherOrderComponent(WrappedComponent);

HOC 可以用于:
1.代码重用、逻辑和引导抽象
2.渲染劫持
3.state 抽象和操作
4.props 处理

七、在构造函数调用 super 并将 props 作为参数传入的作用是啥??

传递 props

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    console.log(this.props);  // { name: 'sudheer',age: 30 }
  }
}

没传递props

class MyComponent extends React.Component {
  constructor(props) {
    super();
    console.log(this.props); // undefined
    // 但是 Props 参数仍然可用
    console.log(props); // Prints { name: 'sudheer',age: 30 }
  }

  render() {
    // 构造函数外部不受影响
    console.log(this.props) // { name: 'sudheer',age: 30 }
  }
}

上面示例揭示了一点。props 的行为只有在构造函数中是不同的,在构造函数之外也是一样的。

八、讲讲什么是 JSX ?

JSX是javascript的语法扩展。它就像一个拥有javascript全部功能的模板语言。它生成React元素,这些元素将在DOM中呈现。React建议在组件使用JSX。在JSX中,我们结合了javascript和HTML,并生成了可以在DOM中呈现的react元素。

JSX 代码本身不能被浏览器读取,必须使用Babel和webpack等工具将其转换为传统的JS

class MyComponent extends React.Component {
  render() {
    let props = this.props;  
    return (
      <div className="my-component">
      <a href={props.url}>{props.name}</a>
      </div>
    );
  }
}

九、为什么不能直接更新 state 呢 ?

如果试图直接更新 state ,则不会重新渲染组件。

 // 错误
 This.state.message = 'Hello world';

需要使用setState()方法来更新 state。它调度对组件state对象的更新。当state改变时,组件通过重新渲染来响应:

// 正确做法
This.setState({message: ‘Hello World’});

十、React 组件生命周期有哪些不同阶段?

1.Initialization:

在这个阶段,组件准备设置初始化状态和默认属性。

2.Mounting:

react 组件已经准备好挂载到浏览器 DOM 中。这个阶段包括componentWillMount和componentDidMount生命周期方法。

3.Updating:

在这个阶段,组件以两种方式更新,发送新的 props 和 state 状态。此阶段包括shouldComponentUpdate、componentWillUpdate和componentDidUpdate生命周期方法。

4.Unmounting:

在这个阶段,组件已经不再被需要了,它从浏览器 DOM 中卸载下来。这个阶段包含 componentWillUnmount 生命周期方法。
除以上四个常用生命周期外,还有一个错误处理的阶段:
Error Handling:在这个阶段,不论在渲染的过程中,还是在生命周期方法中或是在任何子组件的构造函数中发生错误,该组件都会被调用。这个阶段包含了 componentDidCatch 生命周期方法。


image.png

十一、React 组件的生命周期方法?

componentWillMount() – 在渲染之前执行,在客户端和服务器端都会执行。

componentDidMount() – 仅在第一次渲染后在客户端执行。

componentWillReceiveProps() – 当从父类接收到 props 并且在调用另一个渲染器之前调用。

shouldComponentUpdate() – 根据特定条件返回 true 或 false。如果你希望更新组件,请返回true 否则返回 false。默认情况下,它返回 false。

componentWillUpdate() – 在 DOM 中进行渲染之前调用。

componentDidUpdate() – 在渲染发生后立即调用。

componentWillUnmount() – 从 DOM 卸载组件后调用。用于清理内存空间。

十二、什么是 prop drilling,如何避免?

是什么:在构建 React 应用程序时,在多层嵌套组件来使用另一个嵌套组件提供的数据。最简单的方法是将一个 prop 从每个组件一层层的传递下去,从源组件传递到深层嵌套组件,这叫做prop drilling。
prop drilling的主要缺点是原本不需要数据的组件变得不必要地复杂,并且难以维护。
如何避免:使用React Context。通过定义提供数据的Provider组件,并允许嵌套的组件通过Consumer组件或useContext Hook 使用上下文数据。

十三、什么是 React Context?

Context 通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性。

十四、什么是纯函数?

纯函数始终在给定相同参数的情况下返回相同结果。

十五、当调用setState时,React render 是如何工作的?

将"render"分为两个步骤:

1.虚拟 DOM 渲染:

当render方法被调用时,它返回一个新的组件的虚拟 DOM 结构。当调用setState()时,render会被再次调用,因为默认情况下shouldComponentUpdate总是返回true,所以默认情况下 React 是没有优化的。

2.原生 DOM 渲染:

React 只会在虚拟DOM中修改真实DOM节点,而且修改的次数非常少——这是很棒的React特性,它优化了真实DOM的变化,使React变得更快。

十六、React的请求应该放在哪个生命周期中?

目前官方推荐的异步请求是在componentDidmount中进行.

如果有特殊需求需要提前请求,也可以在特殊情况下在constructor中请求:

十七、setState到底是异步还是同步?

先给出答案: 有时表现出异步,有时表现出同步

1.setState只在合成事件和钩子函数中是“异步”的,在原生事件和setTimeout 中都是同步的。
2.setState 的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。
3.setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次setState,setState的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时setState多个不同的值,在更新时会对其进行合并批量更新。

十八、React组件通信如何实现?

React组件间通信方式:

1.父组件向子组件通讯:

父组件可以向子组件通过传 props 的方式,向子组件进行通讯

2.子组件向父组件通讯:

props+回调的方式,父组件向子组件传递props进行通讯,此props为作用域为父组件自身的函数,子组件调用该函数,将子组件想要传递的信息,作为参数,传递到父组件的作用域中

3.兄弟组件通信:

找到这两个兄弟节点共同的父节点,结合上面两种方式由父节点转发信息进行通信

4.跨层级通信:

Context设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言,对于跨越多层的全局数据通过Context通信再适合不过

5.发布订阅模式:

发布者发布事件,订阅者监听事件并做出反应,我们可以通过引入event模块进行通信

6.全局状态管理工具:

借助Redux或者Mobx等全局状态管理工具进行通信,这种工具会维护一个全局状态中心Store,并根据不同的事件产生新的状态

十九、React如何进行组件/逻辑复用?

抛开已经被官方弃用的Mixin,组件抽象的技术目前有三种比较主流:

1.高阶组件:

属性代理
反向继承

2.渲染属性
3.react-hooks

二十、mixin、hoc、render props、react-hooks的优劣如何?

Mixin的缺陷:

  • 组件与 Mixin 之间存在隐式依赖(Mixin 经常依赖组件的特定方法,但在定义组件时并不知道这种依赖关系)

  • 多个 Mixin 之间可能产生冲突(比如定义了相同的state字段)

  • Mixin 倾向于增加更多状态,这降低了应用的可预测性(The more state in your application, the harder it is to reason about it.),导致复杂度剧增

  • 隐式依赖导致依赖关系不透明,维护成本和理解成本迅速攀升:

    • 难以快速理解组件行为,需要全盘了解所有依赖 Mixin 的扩展行为,及其之间的相互影响

    • 组价自身的方法和state字段不敢轻易删改,因为难以确定有没有 Mixin 依赖它

    • Mixin 也难以维护,因为 Mixin 逻辑最后会被打平合并到一起,很难搞清楚一个 Mixin 的输入输出

HOC相比Mixin的优势:

  • HOC通过外层组件通过 Props 影响内层组件的状态,而不是直接改变其 State不存在冲突和互相干扰,这就降低了耦合度
  • 不同于 Mixin 的打平+合并,HOC 具有天然的层级结构(组件树结构),这又降低了复杂度

HOC的缺陷:

  • 扩展性限制: HOC 无法从外部访问子组件的 State因此无法通过shouldComponentUpdate滤掉不必要的更新,React 在支持 ES6 Class 之后提供了React.PureComponent来解决这个问题
  • Ref 传递问题: Ref 被隔断,后来的React.forwardRef 来解决这个问题
  • Wrapper Hell: HOC可能出现多层包裹组件的情况,多层抽象同样增加了复杂度和理解成本
  • 命名冲突: 如果高阶组件多次嵌套,没有使用命名空间的话会产生冲突,然后覆盖老属性
  • 不可见性: HOC相当于在原有组件外层再包装一个组件,你压根不知道外层的包装是啥,对于你是黑盒

Render Props优点:

  • 上述HOC的缺点Render Props都可以解决

Render Props缺陷:

  • 使用繁琐: HOC使用只需要借助装饰器语法通常一行代码就可以进行复用,Render Props无法做到如此简单
  • 嵌套过深: Render Props虽然摆脱了组件多层嵌套的问题,但是转化为了函数回调的嵌套

React Hooks优点:

  • 简洁: React Hooks解决了HOC和Render Props的嵌套问题,更加简洁
  • 解耦: React Hooks可以更方便地把 UI 和状态分离,做到更彻底的解耦
  • 组合: Hooks 中可以引用另外的 Hooks形成新的Hooks,组合变化万千
  • 函数友好: React Hooks为函数组件而生,从而解决了类组件的几大问题:
    • this 指向容易错误
    • 分割在不同声明周期中的逻辑使得代码难以理解和维护
    • 代码复用成本高(高阶组件容易使代码量剧增)

React Hooks缺陷:

  • 额外的学习成本(Functional Component 与 Class Component 之间的困惑)

  • 写法上有限制(不能出现在条件、循环中),并且写法限制增加了重构成本

  • 破坏了PureComponent、React.memo浅比较的性能优化效果(为了取最新的props和state,每次render()都要重新创建事件处函数)

  • 在闭包场景可能会引用到旧的state、props值

  • 内部实现上不直观(依赖一份可变的全局状态,不再那么“纯”)

  • React.memo并不能完全替代shouldComponentUpdate(因为拿不到 state change,只针对 props change)

二十一、redux的工作流程?

Store:

保存数据的地方,你可以把它看成一个容器,整个应用只能有一个Store。

State:

Store对象包含所有数据,如果想得到某个时点的数据,就要对Store生成快照,这种时点的数据集合,就叫做State。

Action:

State的变化,会导致View的变化。但是,用户接触不到State,只能接触到View。所以,State的变化必须是View导致的。Action就是View发出的通知,表示State应该要发生变化了。

Action Creator:

View要发送多少种消息,就会有多少种Action。如果都手写,会很麻烦,所以我们定义一个函数来生成Action,这个函数就叫Action Creator。

Reducer:

Store收到Action以后,必须给出一个新的State,这样View才会发生变化。这种State的计算过程就叫做Reducer。Reducer是一个函数,它接受Action和当前State作为参数,返回一个新的State。

dispatch:

是View发出Action的唯一方法。

然后我们过下整个工作流程:

首先,用户(通过View)发出Action,发出方式就用到了dispatch方法。
然后,Store自动调用Reducer,并且传入两个参数:当前State和收到的Action,Reducer会返回新的State
State一旦有变化,Store就会调用监听函数,来更新View。

到这儿为止,一次用户交互流程结束。可以看到,在整个流程中数据都是单向流动的,这种方式保证了流程的清晰。


image.png

二十二、Hook有哪些优势?

1.减少状态逻辑复用的风险

Hook和 Mixin在用法上有一定的相似之处,但是 Mixin引入的逻辑和状态是可以相互覆盖的,而多个 Hook之间互不影响,这让我们不需要在把一部分精力放在防止避免逻辑复用的冲突上。在不遵守约定的情况下使用 HOC也有可能带来一定冲突,比如 props覆盖等等,使用 Hook则可以避免这些问题。

2.避免地狱式嵌套

大量使用 HOC的情况下让我们的代码变得嵌套层级非常深,使用 HOC,我们可以实现扁平式的状态逻辑复用,而避免了大量的组件嵌套。

3.让组件更容易理解

在使用 class组件构建我们的程序时,他们各自拥有自己的状态,业务逻辑的复杂使这些组件变得越来越庞大,各个生命周期中会调用越来越多的逻辑,越来越难以维护。使用 Hook,可以让你更大限度的将公用逻辑抽离,将一个组件分割成更小的函数,而不是强制基于生命周期方法进行分割。

4.使用函数代替class

相比函数,编写一个 class可能需要掌握更多的知识,需要注意的点也越多,比如 this指向、绑定事件等等。另外,计算机理解一个 class比理解一个函数更快。Hooks让你可以在 classes之外使用更多 React的新特性。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容