10分钟了解 react 引入的 Hooks

“大家好,我是谷阿莫,今天要将的是一个...”,哈哈哈,看到这个题我就想到这个开头。最近react 官方在 2018 ReactConf 大会上宣布 React v16.7.0-alpha(内测) 将引入 Hooks。所以我们有必要了解 Hooks,以及由此引发的疑问。

当然,学习的最好、最直接的方法就是看文档,所以我也非常建议大家去看文档学习,而且还是官方的文档而不是中文版的文档。本文也是楼主在学习过后的一些总结与思考,楼主会把最近学习到的由浅入深,循序渐进,尽可能简洁的分享给大家,希望对大家有帮助。不足之处可在评论区补充,本文讲从以下几个大方面来展开:

  1. 为什么引入Hooks
  2. Hooks使用和注意事项
  3. Hooks的如何解决了已存在的问题
  4. 引入Hooks引发的疑问

为什么引入Hooks?

react官方给出的动机是用来解决长时间使用和维护react过程中遇到的一些难以避免的问题。比如:

  1. 难以重用和共享组件中的与状态相关的逻辑
  2. 逻辑复杂的组件难以开发与维护,当我们的组件需要处理多个互不相关的 local state 时,每个生命周期函数中可能会包含着各种互不相关的逻辑在里面。
  3. 类组件中的this增加学习成本,类组件在基于现有工具的优化上存在些许问题。
  4. 由于业务变动,函数组件不得不改为类组件等等。

在进一步了解之前,我们需要先快速的了解一些基本的 Hooks 的用法。

快速了解 Hooks 的使用

Hooks让我们的函数组件拥有了类似类组件的特性,比如local state、lifecycle,而且还解决了上面提到的一系列问题,它是如何解决这些问题的,下面会在一一指出。首先来快速的看看Hoos的使用,这里讲最主要的两个 Hooks :useState 和 useEffect。先看一个你可能看过很多遍的例子

import { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });
  return (
      <p> {count} </p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
  );
}

useState

useState 这个方法可以为我们的函数组件带来 local state,它接收一个用于初始 state 的值,返回一对变量

const [count, setCount] = useState(0);

// 等价于
var const = useState(0)[0]; // 该state
var setConst = useState(0)[1]; // 修改该state的方法

useEffect

useEffect 可以利用我们组件中的 local state 进行一些带有副作用的操作

useEffect(() => {
  document.title = `You clicked ${count} times`;
});

useEffect 中还可以通过传入第二个参数来决定是否执行里面的操作来避免一些不必要的性能损失,只要第二个参数数组中的成员的值没有改变,就会跳过此次执行。如果传入一个空数组 [ ],那么该 effect 只会在组件 mount 和 unmount 时期执行。

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 如果count没有改变,就跳过此次执行

useEffect 中还可以通过让函数返回一个函数来进行一些清理操作(clean up),比如取消订阅等

useEffect(() => {
  api.subscribe(theId);
  return () => {
      api.unsubscribe(theId)    //clean up
  }
});

useEffect 什么时候执行? 它会在组件 mount 和 unmount 以及每次重新渲染的时候都会执行,也就是会在 componentDidMount、componentDidUpdate、componentWillUnmount 这三个时期执行。

清理函数(clean up)什么时候执行? 它会在前一次 effect执行后,下一次 effect 将要执行前,以及 Unmount 时期执行

注意事项

我们只能在 函数组件 中使用 Hooks,我们也可以在一个组件中使用多组 Hooks。比如:

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    API.subscribe(props.friend.id);
    return () => {
      API.unsubscribe(props.friend.id);
    };
  });

  return isOnline
}

但是这里有一点需要我们注意的就是 我们只能在顶层代码(Top Level)中调用 Hooks,不能在循环或判断语句等里面调用,这样是为了让我们的 Hooks 在每次渲染的时候都会按照 相同的顺序 调用,因为这里有一个跟关键的问题,那就是 useState 需要依赖参照第一次渲染的调用顺序来匹配对于的state,否则 useState 会无法正确返回它对于的state。

Hooks 解决的问题

好了,知道了 Hooks 基本使用后,我们就可以来了解 Hooks 是怎么解决 react 长期存在的问题的。

如何解决 状态有关的逻辑(stateful logic) 的重用和共享问题。

过去对于类似问题的解决方案主要有两个:

  • Render Props 通过props接受一个返回react element的函数,来动态决定自己要渲染的结果;
<DataProvider render={data => (
  <h1>Hello {data.target}</h1>
)}/>
  • 还有就是Higher-Order Components 以一种类似 工厂模式 的方式去生产出具有相同或类似逻辑的组件。
function getComponent(WrappedComponent) {

  return class extends React.Component {
    constructor(props) {
      super(props);
    }
    componentDidMount() {
      // doSomething
    }
    componentWillUnmount() {
      // doSomething
    }
    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
}

但是无论是哪一种方法都会造成组件数量增多,组件树结构的修改,而且有可能出现组件嵌套地狱(wrapper hell)的情况。现在 React 通过 custom Hooks 来解决这个问题

custom Hooks

custom Hooks 并不是一个api,而是一个规则。具体实现就是通过一个函数来封装跟状态有关的逻辑(stateful logic),将这些逻辑从组件中抽取出来。在这个函数中我们可以使用其他的 Hooks,也可以单独进行测试,甚至将它贡献给社区。

import { useState, useEffect } from 'react';

function useCount() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return count
}

比如上面的一个例子,他就是一个 custom Hooks,提取了对 count 的操作。这里需要遵循一个约定,命名要用 use*,这是为了方便我们区分,利于我们维护。可以看到他其实就是一个函数,我们可以在现有的所有其他组件中引用它

function CountStatus() {
  const count = useCount();
  return count;
}

这里的核心概念就是将逻辑提取出来封装在 custom Hooks,然后可以在任何的其他组件中共享这部分逻辑,也可以贡献给社区。所以我也预测在不久的将来,会出现很多的充满想象力的各种用途的 custom Hooks 在社区中出现,极大的提高我们的开发效率。

具有复杂逻辑的组件的开发和维护

前面我们也提到,我们的组件可能会随着开发的进行变得越来越复杂,要处理越来越多的 local State,那么在组件的生命周期函数中就会充斥着各种互不相关的逻辑,这里需要引入官方的比较复杂的例子,先看基于以前类组件的情况:

class FriendStatusWithCounter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0, isOnline: null };
    this.handleStatusChange = this.handleStatusChange.bind(this);
  }

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

  componentWillUnmount() {
    ChatAPI.unsubscribeFromFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

  handleStatusChange(status) {
    this.setState({
      isOnline: status.isOnline
    });
  }
  // ...

经过 Hook 改造后:

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  // ...
}

状态和相关的处理逻辑可以按照功能进行划分,不必散落在各个生命周期中,大大降低了开发和维护的难度。除了这几个hooks还有其他额外的hooks,在此继续了解 Hooks API Reference

伴随 Hooks 的一些思考

hooks让我们的函数组件的功能得到了扩充,拥有了和类组件相似的功能,甚至避免了类组件存在的各种问题,那么就会出现各种的疑问,比如

  • Hooks 引进后, 函数组件 和 类组件 该如何选择?官方关于类似的问题的答复是:

Our goal is for Hooks to cover all use cases for classes as soon as possible. There are no Hook equivalents to the uncommon getSnapshotBeforeUpdate and componentDidCatch lifecycles yet, but we plan to add them soon.

It is a very early time for Hooks, so some integrations like DevTools support or Flow/TypeScript typings may not be ready yet. Some third-party libraries might also not be compatible with Hooks at the moment.

官方的目标是尽可能快的让 Hooks 去覆盖所有的类组件案例,但是现在 Hooks 还处于一个非常早的阶段,各种调试工具、第三方库等都还没有做好对 Hooks 的支持,而且目前也没有可以取代类组件中 getSnapshotBeforeUpdate 和 componentDidCatch 生命做起的 Hooks,不过很快会加上他们。总的来时就是鼓励大家在以后使用 Hooks,对于已存在的类组件不必大规模的去重写,Hooks及Hooks的生态会继续完善,请期待。

  • Hooks 是否可以代替 render-props 和 higher-order components ?前面我们也提到,hooks可以解决后者带来的各种问题,那么 hooks 是否可以代替后者呢?官方的回答:

Often, render props and higher-order components render only a single child. We think Hooks are a simpler way to serve this use case. There is still a place for both patterns (for example, a virtual scroller component might have a renderItem prop, or a visual container component might have its own DOM structure). But in most cases, Hooks will be sufficient and can help reduce nesting in your tree.

大概意思就是,在大多数案例下,hooks 足够应付且更适合,所以优先考虑 hooks。

这是我看到 hooks 后比较关心的两个问题,如果大家想了解更多的问题的话可以到 Hooks FAQ 了解。如果有什么不足或要补充的地方,欢迎评论区提出。

原文地址:https://segmentfault.com/a/1190000016886795

原文地址:https://www.cnblogs.com/lalalagq/p/9898531.html

时间: 2024-10-13 21:36:26

10分钟了解 react 引入的 Hooks的相关文章

Apache Shiro系列三:10分钟入门

一.            介绍 看完这个10分钟入门之后,你就知道如何在你的应用程序中引入和使用Shiro.以后你再在自己的应用程序中使用Shiro,也应该可以在10分钟内搞定. 二.            概述 关于Shiro的废话就不多说了,详情可以看http://www.cnblogs.com/strinkbug/p/6117353.html Apache Shiro可以做什么?http://shiro.apache.org/features.html 答案是很多,但是在这里我们就不展开

10分钟快速构建汽车零售看板

此文已由作者王文开授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 要说整车厂的核心业务是什么,说白了就是两个:一个是造车,一个是卖车:我今天想来聊一聊卖车,也就是整车厂的销售业务. 目前中国的汽车销售模式都是通过经销商的(暂时不考虑那些垂直的汽车电商,不是本文的重点),普通的个人客户是没法直接向整车厂订购车辆,都是通过4S店的渠道进行购买:这也就是说整车厂需要先把车卖给经销商(批售),经销商再把车卖给个人客户(零售):对于整车厂来说,前者相当于是整车批售,后者就是整车零

C# 10分钟完成百度图片提取文字(文字识别)——入门篇

现在图片文字识别已经很成熟了,比如qq长按图片,点击图片识别就可以识别图片的文字,将不认识的.文字数量大的.或者不能赋值的值进行二次可复制功能. 我们现在就基于百度Ai开放平台进行个人文字识别,demo使用的是C#控制台应用程序,后续有需要的可以嫁接到指定项目中使用,比如提供选择图片,点击识别, 获取返回的值.废话不多说,上干货: 总体为: 注册百度账号api,创建自己的应用: 创建vs控制台应用程序,引入动态链接库: 编写代码调试,效果图查看: 总结. 1.创建百度AI文字识别应用   在百度

使用 Chrome 浏览器插件 Web Scraper 10分钟轻松实现网页数据的爬取

本文标签: WebScraper Chrome浏览器插件 网页数据的爬取 使用Chrome 浏览器插件 Web Scraper 可以轻松实现网页数据的爬取,不写代码,鼠标操作,点哪爬哪,还不用考虑爬虫中的登陆.验证码.异步加载等复杂问题. Web Scraper插件 Web Scraper 官网中的简介: Web Scraper Extension (Free!)Using our extension you can create a plan (sitemap) how a web site

[每周翻译]作为一个计算鸡领域相关的学生狗,有毛东西可以让我花10分钟学习然后享受一生的?

原文地址:https://www.quora.com/As-a-computer-science-student-what-can-I-learn-right-now-in-just-10-minutes-that-could-be-useful-for-the-rest-of-my-life 问:作为一个计算鸡领域相关的学生狗,有毛东西可以让我花10分钟学习然后站撸不哭的?我知道这个问题和 What can I learn/know right now in 10 minutes that w

【白话篇】10分钟搞懂字符编码

如上图所示为常见的,让人看了头晕的 几个种编码. 看懂下面几条规则,你就明白他们的关系了. [1]有些人说,GBK严格来说是字符集,而utf-8则是编码,这种区分已经相当模糊了,他们都是"字节到字符的映射关系",所以下面都用编码来说吧. [2] ISO-8859-1 这种编码是单字节编码,衍生于ASCII,表示范围0-255,只要按照ASCII的规则设计的编码,不管是几字节的,都可以和ISO-8859-1兼容. [3]比如说,GBK编码(双字节)能转化成ISO-8859-1编码,是因为

10分钟学会基于ASP.NET的 JQuery实例 (转)

本文介绍如何在ASP.NET(ASP.NET/AJAX)里使用基于JQuery的AJAX技术.(源代码下载见最后) 在使用JQuery前,请到www.jquery.com下载最新版本的js代码,然后再代码里使用 <script src="_scripts/jQuery-1.2.6.js" type="text/javascript"></script>即可,当然,由于微软已经把JQuery集成到VS里,所以你可以到WWW.ASP.NET/aj

如何在excel里面生产条形码(10分钟让你的excel里面出现条形码)

如今快递行业,京东购物,等都在使用条形码管理,那么如何在你的excel里面也生产条形码进行商品管理呢?其实很简单,4步骤学会!10分钟搞定! 1,从下面给出的网址中,下载字体, 2,双击安装字体, 3,在excel里面选择字体 4,内容是有规范的哦,比如:123的条形码,输入的内容是*123*: 截图说明: ===================================华丽的分割线====================================== 字体地址: http://yu

微信小程序详细图文教程-10分钟完成微信小程序开发部署发布(3元获取腾讯云服务器带小程序支持系统)

很多朋友都认为微信小程序申请.部署.发布很难,需要很长时间. 实际上,微信和腾讯云同是腾讯产品,已经提供了10分钟(根据准备资源情况,已完成小程序申请认证)完成小程序开发.部署.发布的方式.当然,实现的是基础功能.但是,可以给学习者很便捷的体验和很好的启发. 不过,随着微信平台和云服务的发展,真担心,程序猿会失业! 目录 一.微信小程序申请 二.服务器设置(申请.部署.域名) 1.申请服务器 2.部署服务器 3.域名申请和配置 三.小程序发布 1.下载DEMO 2.下载开发工具并安装 3.配置参