前端面试系列【001】 - React 高阶组件、Render props 和 hooks 有什么区别,为什么要不断迭代?

3,670 阅读2分钟

这里有两个问题:

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

我们先来看第一个问题,而第一个问题,要讲清楚这三者的区别,那自然要明白三者分别是什么。

React 高阶组件

高阶组件(HOC)是 React 中用于复用组件逻辑的一种技巧。其本质是:

接收一个组件作为参数,返回一个组件的函数

来看个例子就明白了:

function withSubscription(WrapperdComponent, selectData) {
	return class extend React.Component {
		consturctor(props) {
			super(props)
			this.state = {
				data: selectData(DataSource, props)
			}
		}

		render() {
			return <WrapperdComponent data={this.state.data} {...this.props} />
		}
	}
}

高阶组件具有以下优缺点:

  • 优点
    • 逻辑复用
    • 不影响被包裹的组件的内部逻辑
  • 缺点
    • 高阶组件传递给被包裹组件的 props 如果重名的话,会发生覆盖

Render props

Render props 是一种在 React 组件之间使用一个值为函数的 prop 共享代码的技术,具体来说就是:

Render prop 是一个告知组件需要渲染什么内容的函数 prop

来看个例子:

Class DataProvider extends React.Components {
	state = {
		name: "Alice"
	}	
	render() {
		return (
			<div>
				<p>共享数据组件自己内部的 render</p>
				{ this.props.render(this.state) }
			<div/>
		)
	}
}

<DataProvider render={
data => (<p>共享的 render {data.name}</>)
} />

相较于 hooks 和 hoc,render props 使用的场景较少,它具有以下优缺点:

  • 优点:
    • 数据共享
    • 逻辑复用
  • 缺点:
    • 无法在 return 语句外访问数据
    • 嵌套

Hooks

Hooks 是 React 16.8 中新增的特性。它可以让你在不编写 class 的情况下使用 state,lifecycle 等 React 特性。

通过自定义 hook,可以很轻松的实现逻辑复用。

我们来看个例子:

function useSubscription() {
	const data = DataSource.getComments()
	return [data]
}

function CommentList(props) {
	const {data} = props
	const [subData] = useSubscription()
	return (
	<div>
		this is data: {data},
		this is subData: {subData}
	<div/>
	)
}

可以看到 hooks 结构清晰明了,具有以下优点:

  • 使用直观
  • 不存在 hoc 的重名问题
  • 不存在 render props 的嵌套问题
  • 能在 return 之外访问数据

回答

现在已经明白了三者各自是什么,具有什么优缺点,那么最开始的问题就很好回答了。

React 高阶组件、Render props 和 hooks 有什么区别?

三者都能用来进行逻辑复用。区别在于高阶组件为接收组件,对其进行包装,Render props 为在 render 中渲染共享数据,而 hooks 是以函数调用的形式共享数据。

为什么要不断迭代?

在大部分情况下,高阶组件和 Render props 都存在各自的缺陷:

  • 重名问题
  • 嵌套问题
  • 无法在 return 之外访问数据的问题
  • 数据来源不清晰的问题
  • ......

不断迭代是为了解决上述问题,让我们可以用更加简洁的方式实现组件逻辑复用,让写代码变得更加轻松和愉快。