React 相关知识

React 相关知识

1. React 事件机制

React 相关知识_第1张图片
React并不是将click事件绑定到了div的真实DOM上,而是在document处监听了所有的事件,当事件发生并且冒泡到document处的时候,React将事件内容封装并交由真正的处理函数运行。这样的方式不仅仅减少了内存的消耗,还能在组件挂在销毁时统一订阅和移除事件。

除此之外,冒泡到document上的事件也不是原生的浏览器事件,而是由react自己实现的合成事件(SyntheticEvent)。因此如果不想要是事件冒泡的话应该调用event.preventDefault()方法,而不是调用event.stopProppagation()方法。

JSX 上写的事件并没有绑定在对应的真实 DOM 上,而是通过事件代理的方式,将所有的事件都统一绑定在了 document 上。这样的方式不仅减少了内存消耗,还能在组件挂载销毁时统一订阅和移除事件。

另外冒泡到 document 上的事件也不是原生浏览器事件,而是 React 自己实现的合成事件(SyntheticEvent)。因此我们如果不想要事件冒泡的话,调用 event.stopPropagation 是无效的,而应该调用 event.preventDefault。

实现合成事件的目的如下:

  1. 合成事件首先抹平了浏览器之间的兼容问题,另外这是一个跨浏览器原生事件包装器,赋予了跨浏览器开发的能力;
  2. 对于原生浏览器事件来说,浏览器会给监听器创建一个事件对象。如果你有很多的事件监听,那么就需要分配很多的事件对象,造成高额的内存分配问题。但是对于合成事件来说,有一个事件池专门来管理它们的创建和销毁,当事件需要被使用时,就会从池子中复用对象,事件回调结束后,就会销毁事件对象上的属性,从而便于下次复用事件对象。

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

区别:

  • 对于事件名称命名方式,原生事件为全小写,react 事件采用小驼峰;
  • 对于事件函数处理语法,原生事件为字符串,react 事件为函数;

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

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

  1. 兼容所有浏览器,更好的跨平台;
  2. 将事件统一存放在一个数组,避免频繁的新增与删除(垃圾回收)。
  3. 方便 react 统一管理和事务机制。

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

3. React 组件中怎么做事件代理?它的原理是什么?

React基于Virtual DOM实现了一个SyntheticEvent层(合成事件层),定义的事件处理器会接收到一个合成事件对象的实例,它符合W3C标准,且与原生的浏览器事件拥有同样的接口,支持冒泡机制,所有的事件都自动绑定在最外层上。

在React底层,主要对合成事件做了两件事:

  • 事件委派:React会把所有的事件绑定到结构的最外层,使用统一的事件监听器,这个事件监听器上维持了一个映射来保存所有组件内部事件监听和处理函数。
  • 自动绑定:React组件中,每个方法的上下文都会指向该组件的实例,即自动绑定this为当前组件。

4.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,可以复用代码逻辑。

// 自定义一个获取订阅数据的hook
function 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只能在组件顶层使用,不可在分支语句中使用。

总结∶

Hoc、render props和hook都是为了解决代码复用的问题,但是hoc和render props都有特定的使用场景和明显的缺点。hook是react16.8更新的新的API,让组件逻辑复用更简洁明了,同时也解决了hoc和render props的一些缺点。

6. React.Component 和 React.PureComponent 的区别

PureComponent表示一个纯组件,可以用来优化React程序,减少render函数执行的次数,从而提高组件的性能。

在React中,当prop或者state发生变化时,可以通过在shouldComponentUpdate生命周期函数中执行return false来阻止页面的更新,从而减少不必要的render执行。React.PureComponent会自动执行 shouldComponentUpdate。

不过,pureComponent中的 shouldComponentUpdate() 进行的是浅比较,也就是说如果是引用数据类型的数据,只会比较不是同一个地址,而不会比较这个地址里面的数据是否一致。浅比较会忽略属性和或状态突变情况,其实也就是数据引用指针没有变化,而数据发生改变的时候render是不会执行的。如果需要重新渲染那么就需要重新开辟空间引用数据。PureComponent一般会用在一些纯展示组件上。

使用pureComponent的好处:当组件更新时,如果组件的props或者state都没有改变,render函数就不会触发。省去虚拟DOM的生成和对比过程,达到提升性能的目的。这是因为react自动做了一层浅比较。

7. Component, Element, Instance 之间有什么区别和联系?

元素:一个元素element是一个普通对象(plain object),描述了对于一个DOM节点或者其他组件component,你想让它在屏幕上呈现成什么样子。元素element可以在它的属性props中包含其他元素(译注:用于形成元素树)。创建一个React元素element成本很低。元素element创建之后是不可变的。

组件:一个组件component可以通过多种方式声明。可以是带有一个render()方法的类,简单点也可以定义为一个函数。这两种情况下,它都把属性props作为输入,把返回的一棵元素树作为输出。

实例:一个实例instance是你在所写的组件类component class中使用关键字this所指向的东西(译注:组件实例)。它用来存储本地状态和响应生命周期事件很有用。

函数式组件(Functional component)根本没有实例instance。类组件(Class component)有实例instance,但是永远也不需要直接创建一个组件的实例,因为React帮我们做了这些。

引用文章
引用文章

你可能感兴趣的:(1024程序员节,javascript,react.js)