反应:挂钩可以代替HOC和渲染道具吗?

时间:2019-06-02 22:18:00

标签: javascript reactjs react-hooks

React Hooks FAQ中,我们了解到钩子可以代替返回/渲染单个组件的HOC和渲染道具。

我试图更好地理解这一点,以及为什么这是事实。

让我们首先来看一下HOC:

HOC是一个将组件作为参数的函数,将其包装在诸如效果和状态之类的周围逻辑中,然后返回一个新组件。自定义钩子将如何完全替代它?我们仍然需要将输入函数与其他逻辑包装在一起的函数。

看着渲染道具:

渲染道具是我们作为道具传递给另一个组件的组件,然后该组件使用一些新道具来渲染传递的组件。我猜我们可以通过创建一个返回完整组件的自定义钩子,然后在任何需要的组件中使用该钩子,将其替换为钩子。因此,父级不必将组件作为道具传递给子级。那是钩子如何代替渲染道具?

对于钩子如何在最常见的用例中替换HOC和Render Props的解释(最好使用代码示例)将深为感激。

1 个答案:

答案 0 :(得分:3)

HOC和渲染道具有很多不同的用法,因此我不可能一一介绍,但基本上该段指出,在许多情况下,您可以使用HOC /渲染道具带钩。这不会使HOC /渲染道具过时,但是挂钩是您可用来在组件之间共享代码的另一个工具。

HOC /渲染道具的一项常见工作是管理某些数据的生命周期,并将该数据传递给派生组件或子组件。在下面的示例中,目标是获取窗口宽度,包括与之相关的状态管理和事件监听。

HOC版本:

function withWindowWidth(BaseComponent) {
  class DerivedClass extends React.Component {
    state = {
      windowWidth: window.innerWidth,
    }

    onResize = () => {
      this.setState({
        windowWidth: window.innerWidth,
      })
    }

    componentDidMount() {
      window.addEventListener('resize', this.onResize)
    }

    componentWillUnmount() {
      window.removeEventListener('resize', this.onResize);
    }

    render() {
      <BaseComponent {...this.props} {...this.state}/>
    }
  }
  // Extra bits like hoisting statics omitted for brevity
  return DerivedClass;
}

// To be used like this in some other file:

const MyComponent = (props) => {
  return <div>Window width is: {props.windowWidth}</div>
};

export default withWindowWidth(myComponent);

渲染道具版本:

class WindowWidth extends React.Component {
  propTypes = {
    children: PropTypes.func.isRequired
  }

  state = {
    windowWidth: window.innerWidth,
  }

  onResize = () => {
    this.setState({
      windowWidth: window.innerWidth,
    })
  }

  componentDidMount() {
    window.addEventListener('resize', this.onResize)
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.onResize);
  }

  render() {
    return this.props.children(this.state.windowWidth);
  }
}

// To be used like this:

const MyComponent = () => {
  return (
    <WindowWidth>
      {width => <div>Window width is: {width}</div>}
    </WindowWidth>
  )
}

最后但并非最不重要的是钩子版本

const useWindowWidth = () => {
  const [width, setWidth] = useState(window.innerWidth);
  useEffect(() => {
    const onResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, [])
  return width;
}

// To be used like this:

const MyComponent = () => {
  const width = useWindowWidth();
  return <div>Window width is: {width}</div>;
}