乐趣区

关于react.js:铜九银十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 阶段:

setState 是同步异步?为什么?实现原理?

1. setState 是同步执行的

setState 是同步执行的,然而 state 并不一定会同步更新

2. setState 在 React 生命周期和合成事件中批量笼罩执行

在 React 的生命周期钩子和合成事件中,屡次执行 setState,会批量执行

具体表现为,屡次同步执行的 setState,会进行合并,相似于 Object.assign,雷同的 key,前面的会笼罩后面的

当遇到多个 setState 调用时候,会提取单次传递 setState 的对象,把他们合并在一起造成一个新的
繁多对象,并用这个繁多的对象去做 setState 的事件,就像 Object.assign 的对象合并,后一个
key 值会笼罩后面的 key 值

通过 React 解决的事件是不会同步更新 this.state 的. 通过 addEventListener || setTimeout/setInterval 的形式解决的则会同步更新。
为了合并 setState,咱们须要一个队列来保留每次 setState 的数据,而后在一段时间后执行合并操作和更新 state,并清空这个队列,而后渲染组件。

如何在 ReactJS 的 Props 上利用验证?

当应用程序在开发模式下运行时,React 将主动查看咱们在组件上设置的所有 props,以确保它们具备正确的数据类型。对于不正确的类型,开发模式下会在控制台中生成正告音讯,而在生产模式中因为性能影响而禁用它。强制的 propsisRequired定义的。
上面是一组预约义的 prop 类型:

  • React.PropTypes.string
  • React.PropTypes.number
  • React.PropTypes.func
  • React.PropTypes.node
  • React.PropTypes.bool
    例如,咱们为用户组件定义了如下的propTypes

    import PropTypes from "prop-types";
    class User extends React.Component {render() {
        return (
          <>
            <h1>Welcome, {this.props.name}</h1>
            <h2>Age, {this.props.age}</h2>
          </>
        );
      }
    }
    
    User.propTypes = {
      name: PropTypes.string.isRequired,
      age: PropTypes.number.isRequired,
    };

组件通信的形式有哪些

  • ⽗组件向⼦组件通信: ⽗组件能够向⼦组件通过传 props 的⽅式,向⼦组件进⾏通信
  • ⼦组件向⽗组件通信: props+ 回调的⽅式,⽗组件向⼦组件传递 props 进⾏通信,此 props 为作⽤域为⽗组件⾃身的函 数,⼦组件调⽤该函数,将⼦组件想要传递的信息,作为参数,传递到⽗组件的作⽤域中
  • 兄弟组件通信: 找到这两个兄弟节点独特的⽗节点, 联合上⾯两种⽅式由⽗节点转发信息进⾏通信
  • 跨层级通信: Context 设计⽬的是为了共享那些对于⼀个组件树⽽⾔是“全局”的数据,例如以后认证的⽤户、主题或⾸选语⾔,对于逾越多层的全局数据通过 Context 通信再适宜不过
  • 公布订阅模式: 发布者公布事件,订阅者监听事件并做出反馈, 咱们能够通过引⼊ event 模块进⾏通信
  • 全局状态治理⼯具: 借助 Redux 或者 Mobx 等全局状态治理⼯具进⾏通信, 这种⼯具会保护⼀个全局状态中⼼ Store, 并依据不同的事件产⽣新的状态

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 版本差别

react16.8 hooks

React 16 之后有三个生命周期被废除(但并未删除)

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

官网打算在 17 版本齐全删除这三个函数,只保留 UNSAVE_前缀的三个函数,目标是为了向下兼容,

react 16.4 新增

getSnapshotBeforeUpdate

getDerivedStateFromProps

对于废除的生命周期函数,官网会采纳逐渐迁徙的形式来实现版本的迁徙:

16.3:为不平安的生命周期引入别名,UNSAFE_componentWillMount、UNSAFE_componentWillReceiveProps 和 UNSAFE_componentWillUpdate。(旧的生命周期名称和新的别名都能够在此版本中应用。)

将来 16.x 版本:为 componentWillMount、componentWillReceiveProps 和 componentWillUpdate 启用废除告警。(旧的生命周期名称和新的别名都将在这个版本中工作,然而旧的名称在开发模式下会产生一个正告。)

17.0:删除 componentWillMount、componentWillReceiveProps 和 componentWillUpdate。(在此版本之后,只有新的“UNSAFE_”生命周期名称能够应用。)。

React 组件命名举荐的形式是哪个?

通过援用而不是应用来命名组件 displayName。

应用 displayName 命名组件:

export default React.createClass({displayName: 'TodoApp',  // ...})

React 举荐的办法:

export default class TodoApp extends React.Component {// ...}

useEffect 和 useLayoutEffect 的区别

useEffect
基本上 90% 的状况下, 都应该用这个, 这个是在 render 完结后, 你的 callback 函数执行, 然而不会 block browser painting, 算是某种异步的形式吧, 然而 class 的 componentDidMount 和 componentDidUpdate 是同步的, 在 render 完结后就运行,useEffect 在大部分场景下都比 class 的形式性能更好.
useLayoutEffect
这个是用在解决 DOM 的时候, 当你的 useEffect 外面的操作须要解决 DOM, 并且会扭转页面的款式, 就须要用这个, 否则可能会呈现呈现闪屏问题, useLayoutEffect 外面的 callback 函数会在 DOM 更新实现后立刻执行, 然而会在浏览器进行任何绘制之前运行实现, 阻塞了浏览器的绘制.

constructor 为什么不先渲染?

由 ES6 的继承规定得悉,不论子类写不写 constructor,在 new 实例的过程都会给补上 constructor。

所以:constructor 钩子函数并不是不可短少的,子组件能够在一些状况略去。比方不本人的 state,从 props 中获取的状况

参考:前端 react 面试题具体解答
**

React 与 Vue 的 diff 算法有何不同?

diff 算法是指生成更新补丁的形式,次要利用于虚构 DOM 树变动后,更新实在 DOM。所以 diff 算法肯定存在这样一个过程:触发更新 → 生成补丁 → 利用补丁。

React 的 diff 算法,触发更新的机会次要在 state 变动与 hooks 调用之后。此时触发虚构 DOM 树变更遍历,采纳了深度优先遍历算法。但传统的遍历形式,效率较低。为了优化效率,应用了分治的形式。将繁多节点比对转化为了 3 种类型节点的比对,别离是树、组件及元素,以此晋升效率。

  • 树比对:因为网页视图中较少有跨层级节点挪动,两株虚构 DOM 树只对同一档次的节点进行比拟。
  • 组件比对:如果组件是同一类型,则进行树比对,如果不是,则间接放入到补丁中。
  • 元素比对:次要产生在同层级中,通过标记节点操作生成补丁,节点操作对应实在的 DOM 剪裁操作。

以上是经典的 React diff 算法内容。自 React 16 起,引入了 Fiber 架构。为了使整个更新过程可随时暂停复原,节点与树别离采纳了 FiberNode 与 FiberTree 进行重构。fiberNode 应用了双链表的构造,能够间接找到兄弟节点与子节点。整个更新过程由 current 与 workInProgress 两株树双缓冲实现。workInProgress 更新实现后,再通过批改 current 相干指针指向新节点。

Vue 的整体 diff 策略与 React 对齐,尽管不足工夫切片能力,但这并不意味着 Vue 的性能更差,因为在 Vue 3 初期引入过,前期因为收益不高移除掉了。除了高帧率动画,在 Vue 中其余的场景简直都能够应用防抖和节流去进步响应性能。

为什么 React 要用 JSX?

JSX 是一个 JavaScript 的语法扩大,或者说是一个相似于 XML 的 ECMAScript 语法扩大。它自身没有太多的语法定义,也不冀望引入更多的规范。

其实 React 自身并不强制应用 JSX。在没有 JSX 的时候,React 实现一个组件依赖于应用 React.createElement 函数。代码如下:

class Hello extends React.Component {render() {
    return React.createElement(
        'div',
        null, 
        `Hello ${this.props.toWhat}`
      );
  }
}
ReactDOM.render(React.createElement(Hello, {toWhat: 'World'}, null),
  document.getElementById('root')
);

而 JSX 更像是一种语法糖,通过相似 XML 的形容形式,刻画函数对象。在采纳 JSX 之后,这段代码会这样写:

class Hello extends React.Component {render() {return <div>Hello {this.props.toWhat}</div>;
  }
}
ReactDOM.render(
  <Hello toWhat="World" />,
  document.getElementById('root')
);

通过比照,能够清晰地发现,代码变得更为简洁,而且代码构造档次更为清晰。

因为 React 须要将组件转化为虚构 DOM 树,所以在编写代码时,实际上是在手写一棵构造树。而XML 在树结构的形容上天生具备可读性强的劣势。

但这样可读性强的代码仅仅是给写程序的同学看的,实际上在运行的时候,会应用 Babel 插件将 JSX 语法的代码还原为 React.createElement 的代码。

总结: JSX 是一个 JavaScript 的语法扩大,构造相似 XML。JSX 次要用于申明 React 元素,但 React 中并不强制应用 JSX。即便应用了 JSX,也会在构建过程中,通过 Babel 插件编译为 React.createElement。所以 JSX 更像是 React.createElement 的一种语法糖。

React 团队并不想引入 JavaScript 自身以外的开发体系。而是心愿通过正当的关注点拆散放弃组件开发的纯正性。

什么起因会促使你脱离 create-react-app 的依赖

当你想去配置 webpack 或 babel presets。

react 强制刷新

component.forceUpdate() 一个不罕用的生命周期办法, 它的作用就是强制刷新

官网解释如下

默认状况下,当组件的 state 或 props 发生变化时,组件将从新渲染。如果 render() 办法依赖于其余数据,则能够调用 forceUpdate() 强制让组件从新渲染。

调用 forceUpdate() 将以致组件调用 render() 办法,此操作会跳过该组件的 shouldComponentUpdate()。但其子组件会触发失常的生命周期办法,包含 shouldComponentUpdate() 办法。如果标记发生变化,React 仍将只更新 DOM。

通常你应该防止应用 forceUpdate(),尽量在 render() 中应用 this.props 和 this.state。

shouldComponentUpdate 在初始化 和 forceUpdate 不会执行

类组件 (Class component) 和函数式组件 (Functional component) 之间有何不同

  • 类组件不仅容许你应用更多额定的性能,如组件本身的状态和生命周期钩子,也能使组件间接拜访 store 并维持状态
  • 当组件仅是接管 props,并将组件本身渲染到页面时,该组件就是一个 ‘ 无状态组件 (stateless component)’,能够应用一个纯函数来创立这样的组件。这种组件也被称为哑组件(dumb components) 或展现组件

为什么 React 并不举荐优先思考应用 Context?

  • Context 目前还处于试验阶段,可能会在前面的发行版本中有很大的变动,事实上这种状况曾经产生了,所以为了防止给今后降级带来大的影响和麻烦,不倡议在 app 中应用 context。
  • 只管不倡议在 app 中应用 context,然而独有组件而言,因为影响范畴小于 app,如果能够做到高内聚,不毁坏组件树之间的依赖关系,能够思考应用 context
  • 对于组件之间的数据通信或者状态治理,无效应用 props 或者 state 解决,而后再思考应用第三方的成熟库进行解决,以上的办法都不是最佳的计划的时候,在思考 context。
  • context 的更新须要通过 setState()触发,然而这并不是很牢靠的,Context 反对跨组件的拜访,然而如果两头的子组件通过一些办法不影响更新,比方 shouldComponentUpdate() 返回 false 那么不能保障 Context 的更新肯定能够应用 Context 的子组件,因而,Context 的可靠性须要关注

对 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-Intl 的了解,它的工作原理?

React-intl 是雅虎的语言国际化开源我的项目 FormatJS 的一部分,通过其提供的组件和 API 能够与 ReactJS 绑定。

React-intl 提供了两种应用办法,一种是援用 React 组件,另一种是间接调取 API,官网更加举荐在 React 我的项目中应用前者,只有在无奈应用 React 组件的中央,才应该调用框架提供的 API。它提供了一系列的 React 组件,包含数字格式化、字符串格式化、日期格式化等。

在 React-intl 中,能够配置不同的语言包,他的工作原理就是依据须要,在语言包之间进行切换。

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

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

this.setState({
    key1: newState1,
    key2: newState2,
    ...
}, callback) // 第二个参数是 state 更新实现后的回调函数

在 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 间接能够反对。这个办法适宜一些须要长期存储的场景。

对 componentWillReceiveProps 的了解

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

应用益处: 在这个生命周期中,能够在子组件的 render 函数执行前获取新的 props,从而更新子组件本人的 state。能够将数据申请放在这里进行执行,须要传的参数则从 componentWillReceiveProps(nextProps)中获取。而不用将所有的申请都放在父组件中。于是该申请只会在该组件渲染时才会收回,从而加重申请累赘。

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

退出移动版