在2018年React Conf大会上,React团队讲解了目前你们使用React开发过程存在的一些问题并推出了一个使人激动的概念:React Hooks,并介绍hooks如何解决这些问题。恰好我所在的团队前端使用的是react+ts+node这套技术栈,前段时间将react版本升级到了16.8,在这个过程当中使用到了hooks的功能。在这里写下本身的感觉和看法。前端
本文将从如下几部分进行总结:node
在react hooks问世以前,react能提供给组件间复用逻辑采用的是mixin,但这种方式弊端很是多,因此你们基本都是用render props(渲染属性)和HOC(高阶组件)来复用组件间的逻辑。但这两种方式的缺点也是很是明显的,很容易产生「wrapper hell」,即组件很容易臃肿,增长了debugger的成本。react
在稍微复杂的业务逻辑当中,生命周期是绕不过去的问题。有不少场景下在componentDidmount处理的逻辑不得不又在componentDidUpdate从新处理一次,业务被分散在各个不一样的生命周期函数中。 编程
而Hooks的出现,从面向生命周期编程转变为面向业务逻辑编程 数组
虽然Hooks以前能够编写纯函数组件,但它只能是无状态的。很是常见的状况是你编写了一个纯函数组件,但过一段时间你发现得加上一个状态,这时候不得不将纯函数组件改成类组件。这时候得处理this的问题,并且编译器对class也是不友好的。bash
import { useState, useEffect } from 'react'
function Example(props) {
// 声明一个新的状态变量"count"
const [count, setCount] = useState(0);
useEffect(() => {
subscribe(props.number, setCount)
return () => {
unsubscribe(props.number)
}
})
return <div>{count}</div>
}
复制代码
useState会接受一个初始值,而后会返回一个[状态,状态修改器]的二元组。每次从新渲染时,整个函数会从新执行,可是useState会记住上次的值。并且react是根据useState的调用顺序来记得状态归属的:app
const Example = () => {
const [size, setSize] = useState({ width: 100, height: 100 });
const [count, setCount] = useState(0);
}
复制代码
每一次 Example 被渲染,都是第一次 useState 调用得到 size 和 setSize,第二次 useState 调用得到 count 和 setCount。函数
useEffect是用来处理反作用的,至关于之前的componentDidMount和componentDidUpdate。它能够返回一个函数,用来在组件卸载前调用。因此useEffect聚合了componentDidMount,componentDidUpdate和componentWillUnmount的操做。若是props.number没有改变,咱们是不但愿在useEffect订阅/取消订阅里从新执行的,为了实现这个操做,只须要传入一个参数便可。ui
useEffect(() => {
subscribe(props.number, setCount)
return () => {
unsubscribe(props.number)
}
}, [props.number])
复制代码
它是一个数组,只要这个数组中的每个值都不发生变化,则useEffect不须要从新执行。this
在将react升级以后,生命周期函数迁移到函数组件能够按照如下方式来操做:
在react hooks开发的过程当中,共享代码会采起函数组件的形式。约定使用useXXX开头,想重用这些代码,在函数式组件经过调用useXXX便可。
例如咱们能够写这样一个useMountLog,在组件mount的时候打印出一条日志:
const useMountLog = (name) => {
useEffect(() => {
console.log(`${name} mounted`);
});
}
复制代码
这样一来,全部的函数式组件中均可以经过调用useMountLog来使用这个功能:
const Example = () => {
useMountLog('Example')
}
复制代码
再好比能够经过写useWindowWidth这样一个自定义hook来反映当前窗口的宽度
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
});
return width;
}
复制代码
这样就能够在其余函数式组件中使用:
function MyResponsiveComponent() {
const width = useWindowWidth();
return (
<p>Window width is {width}</p>
);
}
复制代码
在上边的例子能够看到,react hooks大大地减小咱们的代码量。而hooks只能在函数式组件中使用,因此能够预测虽然如今react仍然支持类组件,但之后类组件会慢慢得消亡。
React Hooks的出现,将大大地减小react的代码量,解决原来使用react开发遇到的一些问题,也给开发带来了一些变化。包括:
最后,引用 Dan Abramov 在React Conf 2018 上的演讲词结束本文:
“……我曾经疑惑,React 的 Logo 为何是一个原子?后来我想到了这个解释。咱们知道物质由原子组成,是原子的特性决定了物质的外观和行为。就像 React,你能够把用户视图拆成独立的组件,再像原子同样自由组合起来,是组件的特性决定了用户视图的行为。科学家们曾一度认为原子是不可分割的最小单位,直到发现了电子,一种原子内部更小的粒子。事实上,是电子的特征影响了原子的性质。我认为 hooks 就比如电子,与其说它是一个新特性,不如说是已知的 React 特性(state,context,生命周期)的更直接的展示形式,而这四年来咱们却一直对它视而不见。
若是盯着 React 的 logo 看的话,你会发现 hooks 其实一直都在。”