10分钟了解 react 引入的 Hooks
“大家好,我是谷阿莫,今天要将的是一个...”,哈哈哈,看到这个题我就想到这个开头。最近react 官方在 2018 ReactConf 大会上宣布 React v16.7.0-alpha(内测) 将引入 Hooks。所以我们有必要了解 Hooks,以及由此引发的疑问。
React Hooks相关推荐
当然,学习的最好、最直接的方法就是看文档,所以我也非常建议大家去看文档学习,而且还是官方的文档而不是中文版的文档。本文也是楼主在学习过后的一些总结与思考,楼主会把最近学习到的由浅入深,循序渐进,尽可能简洁的分享给大家,希望对大家有帮助。不足之处可在评论区补充,本文讲从以下几个大方面来展开:
- 为什么引入Hooks
- Hooks使用和注意事项
- Hooks的如何解决了已存在的问题
- 引入Hooks引发的疑问
为什么引入Hooks?
react官方给出的动机是用来解决长时间使用和维护react过程中遇到的一些难以避免的问题。比如:
- 难以重用和共享组件中的与状态相关的逻辑
- 逻辑复杂的组件难以开发与维护,当我们的组件需要处理多个互不相关的 local state 时,每个生命周期函数中可能会包含着各种互不相关的逻辑在里面。
- 类组件中的this增加学习成本,类组件在基于现有工具的优化上存在些许问题。
- 由于业务变动,函数组件不得不改为类组件等等。
在进一步了解之前,我们需要先快速的了解一些基本的 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
10分钟了解 react 引入的 Hooks的更多相关文章
- 10分钟学会React Context API
Create-react-app来学习这个功能: 注意下面代码红色的即可,非常简单. 在小项目里Context API完全可以替换掉react-redux. 修改app.js import React ...
- 10 分钟上手 Vue 组件 Vue-Draggable
Vue 综合了 Angualr 和 React 的优点,因其易上手,轻量级,受到了广泛应用.成为了是时下火热的前端框架,吸引着越来越多的前端开发者! 本文将通过一个最简单的拖拽例子带领大家快速上手 V ...
- Apache Shiro系列三,概述 —— 10分钟入门
一.介绍 看完这个10分钟入门之后,你就知道如何在你的应用程序中引入和使用Shiro.以后你再在自己的应用程序中使用Shiro,也应该可以在10分钟内搞定. 二.概述 关于Shiro的废话就不多说了 ...
- 五分钟学习React(三):纯HTML代码搭建React应用
上一期我们使用了React官方的脚手架运行React应用.大家可能会觉得这种方法很繁琐,需要配置各种第三方插件.JQuery时代的前端真是让人怀念.这一期,我就带领大家创建一个"怀旧版&qu ...
- 五分钟学习React(一): 什么是React
在前端的世界里,我们要处理的文件不是太多,而是太少.每天开发项目将html.css.js.图片.字体文件都像大杂烩一般加载都网页上.当应用变得越来越臃肿的时候,会发现js用了那么多全局变量,css的继 ...
- 10分钟详解Spring全家桶7大知识点
Spring框架自2002年诞生以来一直备受开发者青睐,它包括SpringMVC.SpringBoot.Spring Cloud.Spring Cloud Dataflow等解决方案.有人亲切的称之为 ...
- activiti 用户手册中 10分钟 小例子 简单代码搭建 及 其中的 各种坑
看mossle的 5.16 用户手册中的 快速起步:10分钟教程 想自己跑一下,虽然官方文档已经写的非常详细了,但是实际操作中还是遇到各种坑,这里记录下来. 首先官网下载最新的 5版本 full G ...
- 从Mixin到hooks,谈谈对React16.7.0-alpha中即将引入的hooks的理解
为了实现分离业务逻辑代码,实现组件内部相关业务逻辑的复用,在React的迭代中针对类组件中的代码复用依次发布了Mixin.HOC.Render props等几个方案.此外,针对函数组件,在Reac ...
- 在net中json序列化与反序列化 面向对象六大原则 (第一篇) 一步一步带你了解linq to Object 10分钟浅谈泛型协变与逆变
在net中json序列化与反序列化 准备好饮料,我们一起来玩玩JSON,什么是Json:一种数据表示形式,JSON:JavaScript Object Notation对象表示法 Json语法规则 ...
随机推荐
- 【ACM】Binary String Matching
Binary String Matching 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 Given two strings A and B, whose alp ...
- {ldelim},{rdelim} - smarty 内建函数
{ldelim}和{rdelim}用来转义模板的分隔符,缺省为{和}.你也可以用{literal}{/literal}来转义文本块(如Javascript或CSS). 例: {* 在模板外将原样打印分 ...
- JSTL截取字符串以及格式化时间
fn函数里面有很多好用的方法 <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions& ...
- OracleJDK与OpenJDK的区别和联系
OpenJDK原是SunMicrosystems公司为Java平台构建的Java开发环境(JDK)的开源版本,完全自由,开放源码.OracleJDK里面包含的JVM是HotSpotVM,HotSpot ...
- 寻找jar包的好方法
好东西分享下: 下载jar包不用愁 http://maven.outofmemory.cn/
- springboot 学习笔记(七)
(七)springboot整合activemq,消息消费,以及发送对象消息 1.springboot整合activemq发送消息,上一节已经介绍了,现在要对消息队列中的内容进行处理,下面写一个cons ...
- ActionListener 监听事件源产生的事件
用户在窗体上对组件进行一定动作,比如鼠标点击,会产生一些相应的事件,如ActionEvents,ChangeEvents,ItemEvents等,来响应用户的鼠标点击行为.通过实现ActionList ...
- linux 解决 gvfsd-smb-browse CPU 100%占用
原文地址:https://bugzilla.redhat.com/show_bug.cgi?id=1303300 1: sudo vim /etc/samba/smb.conf 2:定位到[globa ...
- npm安装使用淘宝代理的方法(设置registry参数)
公司防火墙问题导致 npm下载失败,安装使用cnpm不知道什么原因抽筋, 还有一个简单的办法,就是npm安装模块时,设置代理: npm install -g vue-cli --registry=ht ...
- spring boot 基础 多环境配置
对于多环境的配置,各种项目构建工具的思路基本上一致,都是通过配置多份不同环境的配置文件来区分. 1. 首先我们先创建不同环境下的属性文件,截图如下: application.properties 是 ...