一、Hooks入门介绍

1、什么是Hooks?

React Hooks是16.8之后新增一个React特性,它可以让你在函数组件中使用state等其它class组件的特性。

2、 为什么要有Hooks?

Class组件:

  • 学习成本高
  • 业务逻辑分散
  • 逻辑复用困难

Hooks:

  • 学习成本低
  • 擅长逻辑复用
  • 会产生很多闭包问题

为什么说Class学习成本高,而hooks学习成本低呢?

第一、生命周期,Class组件绕不开的一点就是生命周期的问题。React15、React16.3、React16.4到React17生命周期有了很多变化。生命周期在class组件中非常重要,面试基本都会问到。如:

  • react生命周期的变化、

  • 如何优化Class组件、

  • 一般在哪个生命周期函数中发送请求?

  • 在这个生命周期函数之前可以发送请求吗?

    第二、this指向的问题,在class组件中因为你不得不使用大量的bind或者箭头函数来定义函数。面试也会问到你:

  • 为什么要这么写?

  • 这么写的好处是什么?

  • 不这样写会产生什么问题?

对比Class,Hooks的学习成本可就太低了。基本上只要能掌握useState和useEffect,那么80%的业务问题都能解决了。

为什么说Class业务逻辑分散,而hooks擅长逻辑复用呢?

我们在学习代码的第一天,就应该知道高内聚、低耦合这六字箴言。设计组件也是一样的,我们应当考虑代码的高可复用性。然而在class组件中,我们实现一个功能,就不得不把相同业务的一些逻辑分散到各个生命周期中。

比如:

如果在组件加载的时候引入一个定时器,那么在组件卸载的时候就一定要清除这个定时器。

componentDidMount(){
  this.timer=setTimeout(this.fun,1000);
}
componenWillUnmount(){
  if(this.timer){
    clearTimeout(this.timer);
  }
}

如果我们有一个请求用户信息的组件,当用户id发生变化的时候,我们就要重新发起请求,那我们就不得不使用两个生命周期函数来处理这个发送请求的逻辑。

componentDidMount(){
  const {useId}=this.props;
  this.loadUserInfo(useId);
}
componentWillReceiveProps(nextProps){
  const {userId:nextUserId}=nextProps;
  const {userId}=this.props;
  if(userId!==nextUserId){
    this.loadUserInfo(nextUserId)
  }
}

注意:在React16版本这个componentWillReceiveProps被标记为unsafe之后,可以使用componentDidUpdate来代替。那么面试官可能就问你:为啥要弃用呢?

而Hooks的业务逻辑就非常聚合了。上面的例子:

useEffect(()=>{
  const timer=setTimeout(fun,1000);
  return ()=>{
    clearTimeout(timer);
  }
},[])
useEffect(()=>{
  loadUserInfo(userId);
},[userId])

为什么说Class复用困难,而Hooks逻辑复用简单?

​ Class组件逻辑复用一般使用的都是HOC和Render Props。但这两者虽然都可以实现逻辑复用,但是并没有让组件和代码变得好用和优美起来,这二者都会存在的一个问题是,逻辑的复用会导致嵌套层级过深,形成嵌套地狱。使用class组件,表单组件、国际化、Redux等混在一块形成一长串的高阶组件的形式大家应该都见过。

​ React Hooks很好的解决了这个问题。组件的复用,完全可以使用自定义Hooks来实现。逻辑共享也成为了社区的主流。什么是逻辑共享?众所周知,组件=UI+逻辑复用,但是当一个组件的ui完全不满足我们的需要,哪怕逻辑完全一样,这个组件的复用性也是为0。但Hooks可以帮助我们讲UI与逻辑分开,实现相同逻辑在不同组件之间的共享。

3、Hooks解决了什么问题?

React Hooks的出现解决了很多问题:

  • 函数组件有了state
  • 解决了函数式组件没有生命周期的问题
  • 解决状态逻辑难以共享的问题

React Hooks 主要解决的问题是状态逻辑共享的问题,是继render-propsHOC之后的第三种状态逻辑共享方案,它不会产生 JSX 嵌套地狱问题。状态逻辑共享其实就是状态逻辑的复用,因为它只共享和复用数据处理的逻辑,不会共享数据本身。

1) 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>
  )
};
2) HOC

学习 HOC 我们只需要记住以下 2 点定义,这里只做简单介绍:

  1. 创建一个函数, 该函数接收一个组件作为输入 除了组件, 还可以传递其他的参数
  2. 基于该组件返回了一个不同的组件.
function withSubscription(WrappedComponent, selectData) {
  returnclass extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        data: selectData(DataSource, props)
      };
    }
    // 一些通用的逻辑处理
    render() {
      // ... 并使用新数据渲染被包装的组件!
      return <WrappedComponent data={this.state.data} {...this.props} />;
    }
  };
}

优点:

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

缺点:

  • 如果,子组件的props跟父组件props相同的时候,子组件自身的 props 值可能会被父组件的props覆盖.
  • 无法清晰的标识数据的来源
  • 可能会产生嵌套地狱
3) Hooks

Hooks也是用来解决状态逻辑共享的问题的。React Hooks 就像一个内置的打平 renderProps 库,我们可以随时创建一个值,与修改这个值的方法。看上去像 function 形式的 setState,其实这等价于依赖注入,与使用 setState 相比,这个组件是没有状态的

function App() {
  const [open, setOpen] = useState(false);
  return (
    <>
      <Button type="primary" onClick={() => setOpen(true)}>
        Open Modal
      </Button>
      <Modal
        visible={open}
        onOk={() => setOpen(false)}
        onCancel={() => setOpen(false)}
      />
    </>
  );
}
优点:
  • hook 可以重命名
  • hook 会清晰地标注数据的来源
  • hook 可以让你在 return 之外使用数据
  • hook 不会嵌套
  • hook的更新数据和状态的粒度要更细更小
  • 简单易懂, 对比 hoc 和 render props 两种方式, 它非常直观, 也更容易理解.
缺点:
  • 会产生闭包问题
  • 对人员素质有了更高的要求,React Hooks模糊了(或者说是抛弃了)生命周期的概念,看似降低了学习门槛,其实是对开发人员的素质有了一个更高的提升,它带来了更高的学习心智(如Hooks生命周期的理解、Hooks Rules的理解、useEffect依赖项的判断等),相比Vue3.0即将推出的Hooks有较高的使用门槛。
  • Hooks能解决组件功能复用,但没有很好地解决JSX的复用问题。
  • 类拥有比函数更丰富的表达能力(OOP),React采用Hooks+Function Component(函数式)的方式其实是一种无奈的选择,试想一个挂载了十几个方法或属性的Class Component,用Function Component来写如何组织代码使得逻辑清晰?这背后其实是函数式编程与面向对象编程两种编程范式的权衡
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码搬运工_田先森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值