React:Hooks 会取代 HOC 和 Render Props 吗?
React: Do Hooks Replace HOCs and Render Props?
从 React Hooks FAQ 中,我们了解到 hooks 可以替代 return/render 单个组件的 HOC 和 Render Props。
我试图更好地理解这一点,以及为什么这是事实。
我们先来看看 HOC:
HOC 是一个函数,它将组件作为参数,将其包装在效果和状态等周围逻辑中,returns 一个新组件。自定义挂钩究竟如何替换它?我们仍然需要用其他逻辑包装输入函数的函数。
查看渲染道具:
render prop 是我们作为 prop 传递给另一个组件的组件,然后使用一些新的 props 渲染传递的组件。我想我们可以通过创建一个 returns 完整组件的自定义挂钩来用挂钩替换它,然后在任何需要的组件中使用该挂钩。因此 parent 不必将组件作为 prop 传递给它的 child。这就是 Hooks 取代 Render Props 的方式吗?
如果能提供有关钩子如何在最常见的用例中替换 HOC 和 Render Prop 的解释(最好是代码示例),我们将不胜感激。
HOC 和渲染道具有许多不同的用途,所以我不可能涵盖所有这些,但基本上该段指出了您使用 HOC/render 道具的许多情况也可以用钩子来实现。这不会使 HOCs/render 道具过时,但钩子是您可以使用的另一种工具,用于在组件之间共享代码。
HOC/render 道具的一项常见工作是管理某些数据的生命周期,并将该数据传递给派生组件或子组件。在下面的示例中,目标是获取 window 宽度,包括 state-management 和与之相关的事件监听。
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() {
return <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>;
}
从 React Hooks FAQ 中,我们了解到 hooks 可以替代 return/render 单个组件的 HOC 和 Render Props。
我试图更好地理解这一点,以及为什么这是事实。
我们先来看看 HOC:
HOC 是一个函数,它将组件作为参数,将其包装在效果和状态等周围逻辑中,returns 一个新组件。自定义挂钩究竟如何替换它?我们仍然需要用其他逻辑包装输入函数的函数。
查看渲染道具:
render prop 是我们作为 prop 传递给另一个组件的组件,然后使用一些新的 props 渲染传递的组件。我想我们可以通过创建一个 returns 完整组件的自定义挂钩来用挂钩替换它,然后在任何需要的组件中使用该挂钩。因此 parent 不必将组件作为 prop 传递给它的 child。这就是 Hooks 取代 Render Props 的方式吗?
如果能提供有关钩子如何在最常见的用例中替换 HOC 和 Render Prop 的解释(最好是代码示例),我们将不胜感激。
HOC 和渲染道具有许多不同的用途,所以我不可能涵盖所有这些,但基本上该段指出了您使用 HOC/render 道具的许多情况也可以用钩子来实现。这不会使 HOCs/render 道具过时,但钩子是您可以使用的另一种工具,用于在组件之间共享代码。
HOC/render 道具的一项常见工作是管理某些数据的生命周期,并将该数据传递给派生组件或子组件。在下面的示例中,目标是获取 window 宽度,包括 state-management 和与之相关的事件监听。
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() {
return <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>;
}