写点什么

React 面试八股文(第二期)

作者:beifeng1996
  • 2022-10-19
    浙江
  • 本文字数:11384 字

    阅读完需:约 1 分钟

React.forwardRef 是什么?它有什么作用?

React.forwardRef 会创建一个 React 组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。这种技术并不常见,但在以下两种场景中特别有用:


  • 转发 refs 到 DOM 组件

  • 在高阶组件中转发 refs

refs 的作用是什么,你在什么样的业务场景下使用 refs

  • 操作 DOM,为什么操作 DOM?

  • 场景

  • 图片渲染好后,操作图片宽高。比如做个放大镜功能

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

(1)哪些方法会触发 react 重新渲染?


  • setState()方法被调用


setState 是 React 中最常用的命令,通常情况下,执行 setState 会触发 render。但是这里有个点值得关注,执行 setState 的时候不一定会重新渲染。当 setState 传入 null 时,并不会触发 render。


class App extends React.Component {  state = {    a: 1  };
render() { console.log("render"); return ( <React.Fragement> <p>{this.state.a}</p> <button onClick={() => { this.setState({ a: 1 }); // 这里并没有改变 a 的值 }} > Click me </button> <button onClick={() => this.setState(null)}>setState null</button> <Child /> </React.Fragement> ); }}
复制代码


  • 父组件重新渲染


只要父组件重新渲染了,即使传入子组件的 props 未发生变化,那么子组件也会重新渲染,进而触发 render


(2)重新渲染 render 会做些什么?


  • 会对新旧 VNode 进行对比,也就是我们所说的 Diff 算法。

  • 对新旧两棵树进行一个深度优先遍历,这样每一个节点都会一个标记,在到深度遍历的时候,每遍历到一和个节点,就把该节点和新的节点树进行对比,如果有差异就放到一个对象里面

  • 遍历差异对象,根据差异的类型,根据对应对规则更新 VNode


React 的处理 render 的基本思维模式是每次一有变动就会去重新渲染整个应用。在 Virtual DOM 没有出现之前,最简单的方法就是直接调用 innerHTML。Virtual DOM 厉害的地方并不是说它比直接操作 DOM 快,而是说不管数据怎么变,都会尽量以最小的代价去更新 DOM。React 将 render 函数返回的虚拟 DOM 树与老的进行比较,从而确定 DOM 要不要更新、怎么更新。当 DOM 树很大时,遍历两棵树进行各种比对还是相当耗性能的,特别是在顶层 setState 一个微小的修改,默认会去遍历整棵树。尽管 React 使用高度优化的 Diff 算法,但是这个过程仍然会损耗性能.

React 的事件和普通的 HTML 事件有什么不同?

区别:


  • 对于事件名称命名方式,原生事件为全小写,react 事件采用小驼峰;

  • 对于事件函数处理语法,原生事件为字符串,react 事件为函数;

  • react 事件不能采用 return false 的方式来阻止浏览器的默认行为,而必须要地明确地调用preventDefault()来阻止默认行为。


合成事件是 react 模拟原生 DOM 事件所有能力的一个事件对象,其优点如下:


  • 兼容所有浏览器,更好的跨平台;

  • 将事件统一存放在一个数组,避免频繁的新增与删除(垃圾回收)。

  • 方便 react 统一管理和事务机制。


事件的执行顺序为原生事件先执行,合成事件后执行,合成事件会冒泡绑定到 document 上,所以尽量避免原生事件与合成事件混用,如果原生事件阻止冒泡,可能会导致合成事件不执行,因为需要冒泡到 document 上合成事件才会执行。

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

React 声明组件的三种方式:


  • 函数式定义的无状态组件

  • ES5 原生方式React.createClass定义的组件

  • ES6 形式的extends React.Component定义的组件


(1)无状态函数式组件 它是为了创建纯展示组件,这种组件只负责根据传入的 props 来展示,不涉及到 state 状态的操作组件不会被实例化,整体渲染性能得到提升,不能访问 this 对象,不能访问生命周期的方法


(2)ES5 原生方式 React.createClass // RFC React.createClass 会自绑定函数方法,导致不必要的性能开销,增加代码过时的可能性。


(3)E6 继承形式 React.Component // RCC 目前极为推荐的创建有状态组件的方式,最终会取代 React.createClass 形式;相对于 React.createClass 可以更好实现代码复用。


无状态组件相对于于后者的区别: 与无状态组件相比,React.createClass 和 React.Component 都是创建有状态的组件,这些组件是要被实例化的,并且可以访问组件的生命周期方法。


React.createClass 与 React.Component 区别:


① 函数 this 自绑定


  • React.createClass 创建的组件,其每一个成员函数的 this 都有 React 自动绑定,函数中的 this 会被正确设置。

  • React.Component 创建的组件,其成员函数不会自动绑定 this,需要开发者手动绑定,否则 this 不能获取当前组件实例对象。


② 组件属性类型 propTypes 及其默认 props 属性 defaultProps 配置不同


  • React.createClass 在创建组件时,有关组件 props 的属性类型及组件默认的属性会作为组件实例的属性来配置,其中 defaultProps 是使用 getDefaultProps 的方法来获取默认组件属性的

  • React.Component 在创建组件时配置这两个对应信息时,他们是作为组件类的属性,不是组件实例的属性,也就是所谓的类的静态属性来配置的。


③ 组件初始状态 state 的配置不同


  • React.createClass 创建的组件,其状态 state 是通过 getInitialState 方法来配置组件相关的状态;

  • React.Component 创建的组件,其状态 state 是在 constructor 中像初始化组件属性一样声明的。

React 组件的 state 和 props 有什么区别?

(1)props


props 是一个从外部传进组件的参数,主要作为就是从父组件向子组件传递数据,它具有可读性和不变性,只能通过外部组件主动传入新的 props 来重新渲染子组件,否则子组件的 props 以及展现形式不会改变。


(2)state


state 的主要作用是用于组件保存、控制以及修改自己的状态,它只能在 constructor 中初始化,它算是组件的私有属性,不可通过外部访问和修改,只能通过组件内部的 this.setState 来修改,修改 state 属性会导致组件的重新渲染。


(3)区别


  • props 是传递给组件的(类似于函数的形参),而 state 是在组件内被组件自己管理的(类似于在一个函数内声明的变量)。

  • props 是不可修改的,所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。

  • state 是在组件中创建的,一般在 constructor 中初始化 state。state 是多变的、可以修改,每次 setState 都异步更新的。

React 中什么是受控组件和非控组件?

(1)受控组件 在使用表单来收集用户输入时,例如<input><select><textearea>等元素都要绑定一个 change 事件,当表单的状态发生变化,就会触发 onChange 事件,更新组件的 state。这种组件在 React 中被称为受控组件,在受控组件中,组件渲染出的状态与它的 value 或 checked 属性相对应,react 通过这种方式消除了组件的局部状态,使整个状态可控。react 官方推荐使用受控表单组件。


受控组件更新 state 的流程:


  • 可以通过初始 state 中设置表单的默认值

  • 每当表单的值发生变化时,调用 onChange 事件处理器

  • 事件处理器通过事件对象 e 拿到改变后的状态,并更新组件的 state

  • 一旦通过 setState 方法更新 state,就会触发视图的重新渲染,完成表单组件的更新


受控组件缺陷: 表单元素的值都是由 React 组件进行管理,当有多个输入框,或者多个这种组件时,如果想同时获取到全部的值就必须每个都要编写事件处理函数,这会让代码看着很臃肿,所以为了解决这种情况,出现了非受控组件。


(2)非受控组件 如果一个表单组件没有 value props(单选和复选按钮对应的是 checked props)时,就可以称为非受控组件。在非受控组件中,可以使用一个 ref 来从 DOM 获得表单值。而不是为每个状态更新编写一个事件处理程序。


React 官方的解释:


要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以使用 ref 来从 DOM 节点中获取表单数据。因为非受控组件将真实数据储存在 DOM 节点中,所以在使用非受控组件时,有时候反而更容易同时集成 React 和非 React 代码。如果你不介意代码美观性,并且希望快速编写代码,使用非受控组件往往可以减少你的代码量。否则,你应该使用受控组件。


例如,下面的代码在非受控组件中接收单个属性:


class NameForm extends React.Component {  constructor(props) {    super(props);    this.handleSubmit = this.handleSubmit.bind(this);  }  handleSubmit(event) {    alert('A name was submitted: ' + this.input.value);    event.preventDefault();  }  render() {    return (      <form onSubmit={this.handleSubmit}>        <label>          Name:          <input type="text" ref={(input) => this.input = input} />        </label>        <input type="submit" value="Submit" />      </form>    );  }}
复制代码


总结: 页面中所有输入类的 DOM 如果是现用现取的称为非受控组件,而通过 setState 将输入的值维护到了 state 中,需要时再从 state 中取出,这里的数据就受到了 state 的控制,称为受控组件。

对 componentWillReceiveProps 的理解

该方法当props发生变化时执行,初始化render时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用this.setState()来更新你的组件状态,旧的属性还是可以通过this.props来获取,这里调用更新状态是安全的,并不会触发额外的render调用。


使用好处: 在这个生命周期中,可以在子组件的 render 函数执行前获取新的 props,从而更新子组件自己的 state。 可以将数据请求放在这里进行执行,需要传的参数则从 componentWillReceiveProps(nextProps)中获取。而不必将所有的请求都放在父组件中。于是该请求只会在该组件渲染时才会发出,从而减轻请求负担。


componentWillReceiveProps 在初始化 render 的时候不会执行,它会在 Component 接受到新的状态(Props)时被触发,一般用于父组件状态更新时子组件的重新渲染。

React 高阶组件、Render props、hooks 有什么区别,为什么要不断迭代

这三者是目前 react 解决代码复用的主要方式:


  • 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。具体而言,高阶组件是参数为组件,返回值为新组件的函数。

  • render props 是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术,更具体的说,render prop 是一个用于告知组件需要渲染什么内容的函数 prop。

  • 通常,render props 和高阶组件只渲染一个子节点。让 Hook 来服务这个使用场景更加简单。这两种模式仍有用武之地,(例如,一个虚拟滚动条组件或许会有一个 renderltem 属性,或是一个可见的容器组件或许会有它自己的 DOM 结构)。但在大部分场景下,Hook 足够了,并且能够帮助减少嵌套。


(1)HOC 官方解释∶


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


简言之,HOC 是一种组件的设计模式,HOC 接受一个组件和额外的参数(如果需要),返回一个新的组件。HOC 是纯函数,没有副作用。


// hoc的定义function withSubscription(WrappedComponent, selectData) {  return class extends React.Component {    constructor(props) {      super(props);      this.state = {        data: selectData(DataSource, props)      };    }    // 一些通用的逻辑处理    render() {      // ... 并使用新数据渲染被包装的组件!      return <WrappedComponent data={this.state.data} {...this.props} />;    }  };
// 使用const BlogPostWithSubscription = withSubscription(BlogPost, (DataSource, props) => DataSource.getBlogPost(props.id));
复制代码


HOC 的优缺点∶


  • 优点∶ 逻辑服用、不影响被包裹组件的内部逻辑。

  • 缺点∶ hoc 传递给被包裹组件的 props 容易和被包裹后的组件重名,进而被覆盖


(2)Render props 官方解释∶


"render prop"是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术


具有 render prop 的组件接受一个返回 React 元素的函数,将 render 的渲染逻辑注入到组件内部。在这里,"render"的命名可以是任何其他有效的标识符。


// DataProvider组件内部的渲染逻辑如下class DataProvider extends React.Components {     state = {    name: 'Tom'  }
render() { return ( <div> <p>共享数据组件自己内部的渲染逻辑</p> { this.props.render(this.state) } </div> ); }}
// 调用方式<DataProvider render={data => ( <h1>Hello {data.name}</h1>)}/>

复制代码


由此可以看到,render props 的优缺点也很明显∶


  • 优点:数据共享、代码复用,将组件内的 state 作为 props 传递给调用者,将渲染逻辑交给调用者。

  • 缺点:无法在 return 语句外访问数据、嵌套写法不够优雅


(3)Hooks 官方解释∶


Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。通过自定义 hook,可以复用代码逻辑。


// 自定义一个获取订阅数据的hookfunction useSubscription() {  const data = DataSource.getComments();  return [data];}// function CommentList(props) {  const {data} = props;  const [subData] = useSubscription();    ...}// 使用<CommentList data='hello' />
复制代码


以上可以看出,hook 解决了 hoc 的 prop 覆盖的问题,同时使用的方式解决了 render props 的嵌套地狱的问题。hook 的优点如下∶


  • 使用直观;

  • 解决 hoc 的 prop 重名问题;

  • 解决 render props 因共享数据 而出现嵌套地狱的问题;

  • 能在 return 之外使用数据的问题。


需要注意的是:hook 只能在组件顶层使用,不可在分支语句中使用。、


参考:前端react面试题详细解答

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

<>  <span id="name" ref={this.spanRef}>{this.state.title}</span>  <span>{     this.spanRef.current ? '有值' : '无值'  }</span></>
复制代码


不可以,render 阶段 DOM 还没有生成,无法获取 DOM。DOM 的获取需要在 pre-commit 阶段和 commit 阶段:

state 和 props 触发更新的生命周期分别有什么区别?

state 更新流程: 这个过程当中涉及的函数:


  1. shouldComponentUpdate: 当组件的 state 或 props 发生改变时,都会首先触发这个生命周期函数。它会接收两个参数:nextProps, nextState——它们分别代表传入的新 props 和新的 state 值。拿到这两个值之后,我们就可以通过一些对比逻辑来决定是否有 re-render(重渲染)的必要了。如果该函数的返回值为 false,则生命周期终止,反之继续;


注意:此方法仅作为性能优化的方式而存在。不要企图依靠此方法来“阻止”渲染,因为这可能会产生 bug。应该考虑使用内置的 PureComponent 组件,而不是手动编写 shouldComponentUpdate()


  1. componentWillUpdate:当组件的 state 或 props 发生改变时,会在渲染之前调用 componentWillUpdate。componentWillUpdate 是 React16 废弃的三个生命周期之一。过去,我们可能希望能在这个阶段去收集一些必要的信息(比如更新前的 DOM 信息等等),现在我们完全可以在 React16 的 getSnapshotBeforeUpdate 中去做这些事;

  2. componentDidUpdate:componentDidUpdate() 会在 UI 更新后会被立即调用。它接收 prevProps(上一次的 props 值)作为入参,也就是说在此处我们仍然可以进行 props 值对比(再次说明 componentWillUpdate 确实鸡肋哈)。



props 更新流程: 相对于 state 更新,props 更新后唯一的区别是增加了对 componentWillReceiveProps 的调用。关于 componentWillReceiveProps,需要知道这些事情:


  • componentWillReceiveProps:它在 Component 接受到新的 props 时被触发。componentWillReceiveProps 会接收一个名为 nextProps 的参数(对应新的 props 值)。该生命周期是 React16 废弃掉的三个生命周期之一。在它被废弃前,可以用它来比较 this.props 和 nextProps 来重新 setState。在 React16 中,用一个类似的新生命周期 getDerivedStateFromProps 来代替它。

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

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

类组件与函数组件有什么异同?

相同点: 组件是 React 可复用的最小代码片段,它们会返回要在页面中渲染的 React 元素。也正因为组件是 React 的最小编码单位,所以无论是函数组件还是类组件,在使用方式和最终呈现效果上都是完全一致的。


我们甚至可以将一个类组件改写成函数组件,或者把函数组件改写成一个类组件(虽然并不推荐这种重构行为)。从使用者的角度而言,很难从使用体验上区分两者,而且在现代浏览器中,闭包和类的性能只在极端场景下才会有明显的差别。所以,基本可认为两者作为组件是完全一致的。


不同点:


  • 它们在开发时的心智模型上却存在巨大的差异。类组件是基于面向对象编程的,它主打的是继承、生命周期等核心概念;而函数组件内核是函数式编程,主打的是 immutable、没有副作用、引用透明等特点。

  • 之前,在使用场景上,如果存在需要使用生命周期的组件,那么主推类组件;设计模式上,如果需要使用继承,那么主推类组件。但现在由于 React Hooks 的推出,生命周期概念的淡出,函数组件可以完全取代类组件。其次继承并不是组件最佳的设计模式,官方更推崇“组合优于继承”的设计概念,所以类组件在这方面的优势也在淡出。

  • 性能优化上,类组件主要依靠 shouldComponentUpdate 阻断渲染来提升性能,而函数组件依靠 React.memo 缓存渲染结果来提升性能。

  • 从上手程度而言,类组件更容易上手,从未来趋势上看,由于 React Hooks 的推出,函数组件成了社区未来主推的方案。

  • 类组件在未来时间切片与并发模式中,由于生命周期带来的复杂度,并不易于优化。而函数组件本身轻量简单,且在 Hooks 的基础上提供了比原先更细粒度的逻辑组织与复用,更能适应 React 的未来发展。

React 中 setState 的第二个参数作用是什么?

setState 的第二个参数是一个可选的回调函数。这个回调函数将在组件重新渲染后执行。等价于在 componentDidUpdate 生命周期内执行。通常建议使用 componentDidUpdate 来代替此方式。在这个回调函数中你可以拿到更新后 state 的值:


this.setState({    key1: newState1,    key2: newState2,    ...}, callback) // 第二个参数是 state 更新完成后的回调函数
复制代码

React setState 调用的原理

具体的执行过程如下(源码级解析):


  • 首先调用了setState 入口函数,入口函数在这里就是充当一个分发器的角色,根据入参的不同,将其分发到不同的功能函数中去;


ReactComponent.prototype.setState = function (partialState, callback) {  this.updater.enqueueSetState(this, partialState);  if (callback) {    this.updater.enqueueCallback(this, callback, 'setState');  }};
复制代码


  • enqueueSetState 方法将新的 state 放进组件的状态队列里,并调用 enqueueUpdate 来处理将要更新的实例对象;


enqueueSetState: function (publicInstance, partialState) {  // 根据 this 拿到对应的组件实例  var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');  // 这个 queue 对应的就是一个组件实例的 state 数组  var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);  queue.push(partialState);  //  enqueueUpdate 用来处理当前的组件实例  enqueueUpdate(internalInstance);}
复制代码


  • enqueueUpdate 方法中引出了一个关键的对象——batchingStrategy,该对象所具备的isBatchingUpdates 属性直接决定了当下是要走更新流程,还是应该排队等待;如果轮到执行,就调用 batchedUpdates 方法来直接发起更新流程。由此可以推测,batchingStrategy 或许正是 React 内部专门用于管控批量更新的对象。


function enqueueUpdate(component) {  ensureInjected();  // 注意这一句是问题的关键,isBatchingUpdates标识着当前是否处于批量创建/更新组件的阶段  if (!batchingStrategy.isBatchingUpdates) {    // 若当前没有处于批量创建/更新组件的阶段,则立即更新组件    batchingStrategy.batchedUpdates(enqueueUpdate, component);    return;  }  // 否则,先把组件塞入 dirtyComponents 队列里,让它“再等等”  dirtyComponents.push(component);  if (component._updateBatchNumber == null) {    component._updateBatchNumber = updateBatchNumber + 1;  }}
复制代码


注意:batchingStrategy 对象可以理解为“锁管理器”。这里的“锁”,是指 React 全局唯一的 isBatchingUpdates 变量,isBatchingUpdates 的初始值是 false,意味着“当前并未进行任何批量更新操作”。每当 React 调用 batchedUpdate 去执行更新动作时,会先把这个锁给“锁上”(置为 true),表明“现在正处于批量更新过程中”。当锁被“锁上”的时候,任何需要更新的组件都只能暂时进入 dirtyComponents 里排队等候下一次的批量更新,而不能随意“插队”。此处体现的“任务锁”的思想,是 React 面对大量状态仍然能够实现有序分批处理的基石。

对 React context 的理解

在 React 中,数据传递一般使用 props 传递数据,维持单向数据流,这样可以让组件之间的关系变得简单且可预测,但是单项数据流在某些场景中并不适用。单纯一对的父子组件传递并无问题,但要是组件之间层层依赖深入,props 就需要层层传递显然,这样做太繁琐了。


Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props。


可以把 context 当做是特定一个组件树内共享的 store,用来做数据传递。简单说就是,当你不想在组件树中通过逐层传递 props 或者 state 的方式来传递数据时,可以使用 Context 来实现跨层级的组件数据传递。


JS 的代码块在执行期间,会创建一个相应的作用域链,这个作用域链记录着运行时 JS 代码块执行期间所能访问的活动对象,包括变量和函数,JS 程序通过作用域链访问到代码块内部或者外部的变量和函数。


假如以 JS 的作用域链作为类比,React 组件提供的 Context 对象其实就好比一个提供给子组件访问的作用域,而 Context 对象的属性可以看成作用域上的活动对象。由于组件 的 Context 由其父节点链上所有组件通 过 getChildContext()返回的 Context 对象组合而成,所以,组件通过 Context 是可以访问到其父组件链上所有节点组件提供的 Context 的属性。

state 是怎么注入到组件的,从 reducer 到组件经历了什么样的过程

通过 connect 和 mapStateToProps 将 state 注入到组件中:


import { connect } from 'react-redux'import { setVisibilityFilter } from '@/reducers/Todo/actions'import Link from '@/containers/Todo/components/Link'
const mapStateToProps = (state, ownProps) => ({ active: ownProps.filter === state.visibilityFilter})
const mapDispatchToProps = (dispatch, ownProps) => ({ setFilter: () => { dispatch(setVisibilityFilter(ownProps.filter)) }})
export default connect( mapStateToProps, mapDispatchToProps)(Link)
复制代码


上面代码中,active 就是注入到 Link 组件中的状态。 mapStateToProps(state,ownProps)中带有两个参数,含义是∶


  • state-store 管理的全局状态对象,所有都组件状态数据都存储在该对象中。

  • ownProps 组件通过 props 传入的参数。


reducer 到组件经历的过程:


  • reducer 对 action 对象处理,更新组件状态,并将新的状态值返回 store。

  • 通过 connect(mapStateToProps,mapDispatchToProps)(Component)对组件 Component 进行升级,此时将状态值从 store 取出并作为 props 参数传递到组件。


高阶组件实现源码∶


import React from 'react'import PropTypes from 'prop-types'
// 高阶组件 contect export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => { class Connect extends React.Component { // 通过对context调用获取store static contextTypes = { store: PropTypes.object }
constructor() { super() this.state = { allProps: {} } }
// 第一遍需初始化所有组件初始状态 componentWillMount() { const store = this.context.store this._updateProps() store.subscribe(() => this._updateProps()); // 加入_updateProps()至store里的监听事件列表 }
// 执行action后更新props,使组件可以更新至最新状态(类似于setState) _updateProps() { const store = this.context.store; let stateProps = mapStateToProps ? mapStateToProps(store.getState(), this.props) : {} // 防止 mapStateToProps 没有传入 let dispatchProps = mapDispatchToProps ? mapDispatchToProps(store.dispatch, this.props) : { dispatch: store.dispatch } // 防止 mapDispatchToProps 没有传入 this.setState({ allProps: { ...stateProps, ...dispatchProps, ...this.props } }) }
render() { return <WrappedComponent {...this.state.allProps} /> } } return Connect}
复制代码

React 中的 setState 和 replaceState 的区别是什么?

(1)setState() setState()用于设置状态对象,其语法如下:


setState(object nextState[, function callback])
复制代码


  • nextState,将要设置的新状态,该状态会和当前的 state 合并

  • callback,可选参数,回调函数。该函数会在 setState 设置成功,且组件重新渲染后调用。


合并 nextState 和当前 state,并重新渲染组件。setState 是 React 事件处理函数中和请求回调函数中触发 UI 更新的主要方法。


(2)replaceState() replaceState()方法与 setState()类似,但是方法只会保留 nextState 中状态,原 state 不在 nextState 中的状态都会被删除。其语法如下:


replaceState(object nextState[, function callback])
复制代码


  • nextState,将要设置的新状态,该状态会替换当前的 state。

  • callback,可选参数,回调函数。该函数会在 replaceState 设置成功,且组件重新渲染后调用。


总结: setState 是修改其中的部分状态,相当于 Object.assign,只是覆盖,不会减少原来的状态。而 replaceState 是完全替换原来的状态,相当于赋值,将原来的 state 替换为另一个对象,如果新状态属性减少,那么 state 中就没有这个状态了。

如何将两个或多个组件嵌入到一个组件中?

可以通过以下方式将组件嵌入到一个组件中:


class MyComponent extends React.Component{    render(){        return(                      <div>                <h1>Hello</h1>                <Header/>            </div>        );    }}class Header extends React.Component{    render(){        return            <h1>Header Component</h1>      };}ReactDOM.render(    <MyComponent/>, document.getElementById('content'));
复制代码

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

组件状态的改变可以因为props的改变,或者直接通过setState方法改变。组件获得新的状态,然后 React 决定是否应该重新渲染组件。只要组件的 state 发生变化,React 就会对组件进行重新渲染。这是因为 React 中的shouldComponentUpdate方法默认返回true,这就是导致每次更新都重新渲染的原因。


当 React 将要渲染组件时会执行shouldComponentUpdate方法来看它是否返回true(组件应该更新,也就是重新渲染)。所以需要重写shouldComponentUpdate方法让它根据情况返回true或者false来告诉 React 什么时候重新渲染什么时候跳过重新渲染。


用户头像

beifeng1996

关注

还未添加个人签名 2022-09-01 加入

还未添加个人简介

评论

发布
暂无评论
React面试八股文(第二期)_React_beifeng1996_InfoQ写作社区