Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

初玩 react-hooks #72

Open
jyzwf opened this issue Mar 30, 2019 · 0 comments
Open

初玩 react-hooks #72

jyzwf opened this issue Mar 30, 2019 · 0 comments

Comments

@jyzwf
Copy link
Owner

jyzwf commented Mar 30, 2019

对于熟悉react的开发的人来说,react hooks 并不陌生,它从去年被提出这个概念的时候,就引起了很大的关注,今年初,它终于被写进了正式版。之前一直处于观望状态,但既然已经定稿了,就想来试试,所以就拿了最近的一个项目来练手。

react hooks 简介

react 为何会出现

  1. 在组件之前很难复用有状态的逻辑
    之前我们在使用react的时候,如果组件被拆分的很细,同时需要把一些数据从顶层向下传递时,就会在render里使用props一层一层往下传,从而出现可怕的wrapper hell:
    image
    这样如果其中一处出现了bug,那我们就要一层一层的去找这个数据是从哪里传递下来的,awful😑😑。
    其次如果我们有一些公共逻辑需要在一些组件里面共用,常见的做法就是封装为高阶组件,最后返回一个组件,这样在 React DevTools 中就又会增加一层 wrapper

  2. 复杂组件变得难以理解
    一些state都被堆砌在顶层,同时在生命周期钩子中充斥着一些并不相关联的副作用等,如果时间长久了再回来看代码,会有一头雾水的感觉,这他妈是我写的代码吗🙃🙃

  3. class 的语法糖无论对自己还是机器都难以理解
    首先,我们在调用事件的时候,需要绑定this,虽然在babel层面上可以解决繁琐的绑定,但语法糖也变得越来也多,class的写法从而变得稀奇古怪,同时你可能还会忘记调用super(props),从而不能使用this。同时官方也说到,使用class 并不利于优化以及对代码压缩以及热加载并不友好。

以上三点是自己结合react hooks 的 Motivation,以及自己在编写代码时感受的看法。

react的出现正是解决如上问题,他让react 变得更像 react。我们可以编写函数式组件,但该组件能拥有属于自己的state,同时一些逻辑能抽离到外面,其他组件使用时,拿来即用就可。

react 官方只提供了如下几个 hooks api,但用户可以使用这几个api,构建出属于自己的自定义hooks,
image

react 实践

上面讲了一些基本概念,具体的api使用可官网上了解。下面就直接来看看怎么使用。
在项目中我需要实现一个播放器的功能:
image
想当然的我们会使用html5的audio标签,这里我使用了react-use中的useAudio,并对其做了简单的封装。
我们先来看 useAudio 是怎么实现的,它将timeisPlayingduration等一些状态量调用useState来形成一个新对象,同时使用ref 来指定当前的audio dom元素,最后声明一些方法来改变state,这样关于audio的逻辑就完全被封装在了 这个hooks中。
但该hooks 并不能满足我对于点击进度条时候,播放进度需要同时改变的需求,所以我需要对他再次封装。
下面是最终的代码:

export default function useAudio({
  src,
  progressBar,
}) {
  const [audio, state, audioControls] = _useAudio({
    src,
  });

  const { left, width } = progressBar.current
    ? progressBar.current.getBoundingClientRect()
    : { left: 0, width: 0 };

  const { duration } = state;

  const controls = {
    ...audioControls,
    clickBar: (event) => {
      const dis = event.pageX - left;
      const rate = dis < 0 ? 0 : dis / width;
      controls.seek(duration * rate);
    },
  };

  return [audio, state, controls];
}

该hook 需要src用于audio的音频来源,progressBar 为进度条额dom元素,由调用useRef产生。点击进度条同步的功能的实现思路就是判断点击的位置占总长度的百分之多少,知道百分比之后就可知道了当前播放占总时长的百分比,从而调用useAudio的 seek 方法来改变时长,进而引发组件的重新渲染。具体使用:
image
注意到这里使用了两个useEffect,一个用于更新当前的进度条的播放长度,另一个用于在不同的tab切换时,暂停当前的audio。我们看到,第二个useEffect传递了第二个参数,这个参数好比class组件中的shouldComponentUpdate,只有在该参数变化时,useEffect才会重新执行传入函数,这样省去了不必要的渲染。

上面只是简单介绍了自己在第一次hooks的使用,写的比较简单,具体的api使用并没有详解,因为网上已经有了更加详解的介绍了。同时自己在重构另一个项目,在完成该重构之后再来完善该部分实践。😊😊

一些感受

hooks 确实让我少了props 传递的烦恼,(也可能是自己之前写法的问题,,啊哈哈),同时在class 转hooks是可以先想像一下class的写法,然后在对照hooks的几个api来重构,这样会快很多。

未完待续...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant