使用React Hook提高代码复用性

更新日期: 2019-05-04阅读: 2.5k标签: 代码

Hook 简介

Hook 是 react 16.8 的新增特性。是对 React 函数组件的一种扩展,通过提供一些特殊的函数,让无状态的组件拥有状态组件才拥有的能力。

没有Hook之前写组件有两种形式,分别为

  • 函数组件
  • class组件

函数组件特点如下

  1. 所有的数据都是依赖props传入的,没有内部state
  2. 没有生命周期
  3. 没有this(组件实例)

实际开发中因为业务复杂,一般使用函数组件无法满足,所以大家默认都是使用class组件进行开发,这是一个不会出错的选择。函数组件大家平时应该都挺少会去用的,因为函数组件能提供的功能比较局限。但是引入Hook后,函数的能力就被扩展了许多,因为函数的特性,非常适合抽象成可复用的组件。


解决哪些问题

不同组件间与状态有关的逻辑复用问题

平时写组件的方式就是通过props传递给下一个组件,有些简单的情况这样也挺好的。但是当项目不断迭代,会发现当组件被多个模块多次引用,还是会多写一些重复的逻辑。因为受到到状态或者生命周期的影响,导致这部分逻辑却又很难拆出来。

引入Hook就可以将受状态或生命周期影响的组件抽出来。

业务发展导致组件日益庞大

最外层的代码集中维护许多state状态,导致页面引入越来越多毫无关联的模块,代码的可读性大大降低,有时候因为多个生命周期里面有大量不相关的逻辑,这样杂乱的代码容易引起bug,也增加了其它开发人员维护的难度。

Hook将组件中每一个相关的小模块拆分成一个函数,这样能够让组件即使庞大结构也是清晰的。


用法

  • State Hook: 在函数组件中使用state
  • Effect Hook: 在函数组件中使用生命周期
  • Custom Hook: 自定义Hook,可以将组件逻辑提取到函数中。(注意:自定义 Hook 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook)

Hook 规则

Hook 本质就是 JavaScript 函数,但是在使用它时需要遵循两条规则

  • 只在最顶层使用 Hook(不要在循环,条件或嵌套函数中调用)

  • 只在 React 函数中调用 Hook

ESLint 插件

强制执行 hooks 的最佳实践

eslint-plugin-react-hooks


如何使用

详细的一些概念官方文档已经写得很全面了,可以参考:Hook的官方文档

接下来就用一个实际的例子来说明一下State Hook的使用

示例

产品第一版本需求如下:

现在有 小A,小B 两位同学,每位同学都处于未穿鞋的状态,小A穿鞋需要2s,小B穿鞋需要5s,在页面一中用文字描述两位同学的穿鞋状态变更( 如果小A正在穿鞋中,则在页面上显示 '小A正在穿鞋子',如果小A已经穿好了鞋子,则将文字替换为 '小A已经穿好鞋子')

使用class组件实现如下:

src/demo1.js

import React from "react";

class Page extends React.Component {
  state = {
    data: [
      { id: 1, name: "小A", time: "2000" },
      { id: 2, name: "小B", time: "5000" }
    ]
  };

  start(item) {
    this.setState({
      [item.id]: "穿鞋子"
    });

    setTimeout(() => {
      this.setState({
        [item.id]: "穿好鞋子"
      });
    }, item.time);
  }

  componentDidMount() {
    this.state.data.forEach(item => {
      this.start(item);
    });
  }

  render() {
    return (
      <div>
        {this.state.data.map(item => {
          return (
            <h1 key={item.id}>
              {this.state[item.id] === "穿鞋子"
                ? `${item.name}正在穿鞋子...`
                : `${item.name}已经穿好鞋子了`}
            </h1>
          );
        })}
      </div>
    );
  }
}

export default Page;

使用Hook组件实现如下:

自定义hook如下:

src/useHook.js

import React, { useState } from "react";

function useHook(item) {
  const [status, setStatus] = useState("穿鞋子");

  setTimeout(() => {
    setStatus("穿好鞋子");
  }, item.time);

  return (
    <h1 key={item.id}>
      {status === "穿鞋子"
        ? `${item.name}正在穿鞋子...`
        : `${item.name}已经穿好鞋子了`}
    </h1>
  );
}

export default useHook;

引用hook的函数组件

src/hookDemo1.js

import React from "react";
import useHook from "./useHook";

function Page() {
  const data = [
    { id: 1, name: "小A", time: "2000" },
    { id: 2, name: "小B", time: "5000" }
  ];
  return (
    <div>
      {data.map(item => {
        return useHook(item);
      })}
    </div>
  );
}

export default Page;

好了,实现完上面的需求,现在觉得hook的好处并没有什么体现,接下来产品又发布了第二版需求,要求我们在另一个页面显示另外两位同学的状态。需求如下:

现在有 小C,小D 两位同学,每位同学都处于未穿鞋的状态,小A穿鞋需要4s,小B穿鞋需要8s,在页面二中用文字描述两位同学的穿鞋状态变更( 如果小A正在穿鞋中,则在页面上显示 '小C正在穿鞋子',如果小C已经穿好了鞋子,则将文字替换为 '小C已经穿好鞋子')

接下来再第一个版本的基础上来实现第二个需求

使用class组件实现如下:

src/demo2.js

import React from "react";

class Page extends React.Component {
  state = {
    data: [
      { id: 1, name: "小C", time: "4000" },
      { id: 2, name: "小D", time: "8000" }
    ]
  };

  start(item) {
    this.setState({
      [item.id]: "穿鞋子"
    });

    setTimeout(() => {
      this.setState({
        [item.id]: "穿好鞋子"
      });
    }, item.time);
  }

  componentDidMount() {
    this.state.data.forEach(item => {
      this.start(item);
    });
  }

  render() {
    return (
      <div style={{ color: "lightblue" }}>
        {this.state.data.map(item => {
          return (
            <h1 key={item.id}>
              {this.state[item.id] === "穿鞋子"
                ? `${item.name}正在穿鞋子...`
                : `${item.name}已经穿好鞋子了`}
            </h1>
          );
        })}
      </div>
    );
  }
}

export default Page;

使用Hook组件实现如下:

src/hookDemo2.js

import React from "react";
import useHook from "./useHook";

function Page() {
  const data = [
    { id: 1, name: "小C", time: "4000" },
    { id: 2, name: "小D", time: "8000" }
  ];
  return (
    <div style={{ color: "lightblue" }}>
      {data.map(item => {
        return useHook(item);
      })}
    </div>
  );
}

export default Page;

第二次的代码明显比第一次少了许多,而且如果之后产品如果增加了一个状态,那明显使用Hook实现的方式可以更快的适应需求的变更,代码的维护性也变高了许多。看完代码应该就能很好的理解hook的使用了吧,具体代码的运行点击在线演示查看:在线演示


总结

Hook给我们带来的就是在函数的基础上可以加入状态和生命周期等函数不曾有的特性,这个特性的加入能够让我们更好的抽象组件,提高代码的复用性。


来自:https://segmentfault.com/a/1190000019067303


链接: https://fly63.com/article/detial/3195

不要浪费时间写完美代码

一个系统可以维持5年,10年,甚至20年以上,但是代码和设计模式的生命周期非常短,当对一个解决方案使用不同的方法进行迭代的时候,通常只能维持数月,数日,甚至几分钟的时间

Google内部在代码质量上的实践

良好的编程习惯涉及到很多方面,但在软件行业内,大多数的公司或组织都不会把良好的编程习惯列为主要关注点。 例如,具有可读性和可维护性的代码比编写好的测试代码或使用正确的工具更有意义,前者的意义在于可以让代码更易于理解和修改。

减少嵌套,降低代码复杂度

减少嵌套会让代码可读性更好,同时也能更容易的找出bug,开发人员可以更快的迭代,程序也会越来越稳定。简化代码,让编程更轻松!

关于 Google 发布的 JS 代码规范

Google为了那些还不熟悉代码规范的人发布了一个JS代码规范。其中列出了编写简洁易懂的代码所应该做的最佳实践。代码规范并不是一种编写正确JavaScript代码的规则,而是为了保持源代码编写模式一致的一种选择。

你解决的问题比你编写的代码更重要!

程序员似乎忘记了软件的真正目的,那就是解决现实问题。您编写的代码的目的是为了创造价值并使现有世界变得更美好,而不是满足您对自我世界应该是什么的以自我为中心的观点。有人说:如果你拥有的只是一把锤子,那么一切看起来都像钉子一样

tinymce与prism代码高亮实现及汉化的配置

TinyMCE是一个轻量级的基于浏览器的所见即所得编辑器,由JavaScript写成。它对IE6+和Firefox1.5+都有着非常良好的支持。功能方强大,并且功能配置灵活简单。另一特点是加载速度非常快的。

js函数式编程与代码执行效率

函数式编程对应的是命令式编程, 函数式编程的核心当然是对函数的运用. 而高阶函数(Higher-order)是实现函数式编程的基本要素。高阶函数可以将其他函数作为参数或者返回结果。所以JS天生就支持函数式编程

接手代码太烂,要不要辞职?

朋友发表了一条说说:入职新公司,从重构代码到放弃”,我就问他怎么了?他说,刚进一家新公司,接手代码太烂,领导让我先熟悉业务逻辑,然后去修复之前项目中遗留的bug,实在不行就重构

js高亮显示关键词_页面、搜索关键词高亮显示

页面实现关键词高亮显示:在项目期间遇到一个需求,就是搜索关键词时需要高亮显示,主要通过正则匹配来实现页面关键词高亮显示。在搜索结果中高亮显示关键词:有一组关键词数组,在数组中筛选出符合关键字的内容并将关键字高亮

写优雅的代码,做优雅的程序员

软件工程学什么? 学计算机,写程序,做软件,当程序员。听说学计算机很辛苦? 是的,IT行业加班现象严重。在计算机世界里,技术日新月异,自学能力是程序员最重要的能力之一。选了这个专业,就要时刻保持好奇心和技术嗅觉,不能只满足于完成课内作业。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!