# 进阶知识点

# 1.HOC 是什么?相比 mixins 有什么优点?

function add(a, b) {
  return a + b
}
function withLog(fn) {
  function wrapper(a, b) {
    const result = fn(a, b)
    console.log(result)
    return result
  }
  return wrapper
}
const withLogAdd = withLog(add)
withLogAdd(1, 2)
1
2
3
4
5
6
7
8
9
10
11
12
13

其实这个做法在函数式编程里称为高阶函数,大家都知道 React 的思想中是存在函数式编程的,高阶组件和高阶函数就是同一个东西。我们实现一个函数,传入一个组件,然后在函数内部再实现一个函数去扩展传入的组件,最后返回一个新的组件,这就是高阶组件的概念,作用就是为了更好的复用代码。

其实 HOC 和 Vue 中的 mixins 作用是一支的,并且在早期 React 也是使用 mixins 的方式。但是在使用 class 的方式常见组件以后,mixins 的方式就不能使用了,并且其实 mixins 也是存在一些问题的:

  • 隐含了一些依赖,比如我在组件中写了某个state并且在mixin中使用了,就这存在了一个依赖关系。万一下次别人要移除它,就得去mixin中查找依赖
  • 多个mixin中可能存在相同命名的函数,同时代码组件中也不能出现相同命名的函数,否则就是重写了
  • 雪球效应,虽然我一个组件合适使用者同一个mixin,但是一个mixin会被多个组件使用,可能会存在需求使得mixin修改原来的函数或者新增更多的函数,这安阳可能就会产生一个维护成本。

# 2.事件机制

React 其实自己实现了一套事件机制,首先我们考虑一下一下代码:

const Test = ({lsit,handleClick}) => ({
  list.map(item, index) => (
    <span onClick={handleClick} key={index}>{index}</span>
  )
})
1
2
3
4
5

以上类似代码想必大家经常会写到,但是你是否考虑过点击事件是否绑定到每一个标签上?实际当然不是,JSX 上写事件并没有绑定在对应的真实 DOM 上,而是通过事件代理的方式,将所有的事件统一绑定在了document上。这种的方式不仅减少了内存消耗,还能再组件挂载销毁是统一订阅和移除事件。

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

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