面试官: 谈一谈 HOC、Render props、Hooks

  • 2020 年 3 月 11 日
  • 筆記

在以前我们可能会看到很多文章在分析 HOC 和 render props, 但是在 2020 年 ,我们有了新欢 “hook” .

本篇文章会分析 hook , render props 和 HOC 三种模式的优缺点. 让你彻底理解这三种模式. 并且, 告诉你为何应该尽可能使用 hook.

HOC

创建 HOC 的方式

学习 HOC 我们只需要记住以下 2 点定义:

  1. 创建一个函数, 该函数接收一个组件作为输入除了组件, 还可以传递其他的参数
  2. 基于该组件返回了一个不同的组件.

代码如下:

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} />;      }    };  }

HOC 的优点

  • 不会影响内层组件的状态, 降低了耦合度

HOC 的缺点

  • 固定的 props 可能会被覆盖.
<MyComponent    x="a"    y="b"  />

这 2 个值,如果跟高阶组件的值相同, 那么 x,y 都会被来自高阶组件的值覆盖.

// 如果 withMouse 和 withPage 使用了同样的 props, 比如 x , y.  // 则会有冲突.  export default withMouse(withPage(MyComponent));
  • 它无法清晰地标识数据的来源

withMouse(MyComponent) 它不会告诉你组件中包含了哪些 props , 增加了调试和修复代码的时间.

render props

功能: 将一个组件内的 state 作为 props 传递给调用者, 调用者可以动态的决定如何渲染.

创建 render props 的方式

  1. 接收一个外部传递进来的 props 属性
  2. 将内部的 state 作为参数传递给调用组件的 props 属性方法.

代码如下:

class Mouse extends React.Component {    constructor(props) {      super(props);      this.state = { x: 0, y: 0 };    }      render() {      return (        <div style={{ height: '100%' }}>          // 使用 render props 属性来确定要渲染的内容          {this.props.render(this.state)}        </div>      );    }  }  // 调用方式:  <Mouse render={mouse => (    <p>鼠标的位置是 {mouse.x},{mouse.y}</p>  )}/>

缺点

  • 无法在 return 语句外访问数据

它不允许在 return 语句之外使用它的数据. 比如上面的例子, 不能在 useEffect 钩子或组件中的任何其他地方使用 x 和 y 值, 只能在 return 语句中访问.

  • 嵌套

它很容易导致嵌套地狱. 如下代码:

const MyComponent = () => {    return (      <Mouse>        {({ x, y }) => (          <Page>            {({ x: pageX, y: pageY }) => (              <Connection>                {({ api }) => {                  // yikes                }}              </Connection>            )}          </Page>        )}      </Mouse>    )  };

基于上面的两种方式,都有他们的缺点,那我们来到最香的解决方案: hook

hook

我们来看一个例子:

const { x, y } = useMouse();  const { x: pageX, y: pageY } = usePage();    useEffect(() => {    }, [pageX, pageY]);

从上面的代码可以看出, hook 有以下的特性. 它解决了上面 hoc 和 render props 的缺点.

  • hook 可以重命名

如果 2 个 hook 暴露的参数一样,我们可以简单地进行重命名.

  • hook 会清晰地标注来源

从上面的例子可以简单地看到, x 和 y 来源于 useMouse. 下面的 x, y 来源于 usePage.

  • hook 可以让你在 return 之外使用数据
  • hook 不会嵌套
  • 简单易懂, 对比 hoc 和 render props 两种方式, 它非常直观, 也更容易理解.

总结

在 hook、render props 和 HOC(higher-order components) 之间选择时,应该尽可能使用 hook.

参考资料

[1]

参考文章: https://dev.to/bettercodingacademy/react-hooks-vs-render-props-vs-higher-order-components-1al0