React函数组件和hooks绝配论
这边会借助函数式编程领域的纯函数和副作用的概念,通过类比的方式介绍什么是Hooks,同时强调Hooks与函数组件的紧密联系
直接提出两个疑问
什么是纯函数?
Hooks到底是什么?
背景
React 对 UI 的理想模型是 UI=f(state),其中 UI 是视图,state是应用状态,f是渲染过程,函数组件相对于类组件更加贴近这模型,但早期的函数组件功能与类组件仍有差距,直到官方在v16.8.0推出了Hooks,函数组件逐渐后来者居上。
纯函数
当一个函数满足如下条件时。就会被认为是一个纯函数:
- 函数无论被调用多少次,只要参数相同,返回值就一定相同,这一过程不受外部状态或者 IO 操作的影响;
- 函数被调用时不会产生 副作用,即不会修改传入的引用参数,不会改变外部状态,不会触发IO操作,也不会调用其他会产生副作用的函数;
你可能有新的疑问:外部状态 是什么?看一下下面这段js代码,这是一个最简单的纯函数,对于给定的 a和 b,返回值永远是两者之和:
const func = (a,b) => {
return a + b;
}
外部状态: 除了参数a,b其他的都是外部状态
用纯函数的概念来写一个React函数组件,对给定的props a 和 b,每次渲染时都会返回相同的元素:
const Component = ({ a, b }) => {
return (
<div> {a} </div>
<div> {b} </div>
)
}
这样子的纯函数组件除了props、JSX外,几乎没有使用React组件的所有其他特性 ———— 对于纯函数组件来说,这些其他特性全部都是外部状态和副作用
换句话说,如果想让函数组件使用其他特性,只要让他以某种方式,去访问函数的外部状态,或者执行副作用就好了。Hooks就是这样一套为函数组件设计的,用于访问React内部状态或执行副作用操作,以函数形式存在的 React API
Hooks
在上面的纯函数组件中加入 Hooks,让函数组件具有了操作state的能力:
const Component = ({ a, b }) => {
const [m, setM] = useState(a)
const [n, setN] = useState(b)
return (
<div> {m} <button onClick={() => setM(m + 1)}>+m</button></div>
<div> {n} <button onClick={() => setM(n + 1)}>+n</button></div>
)
}
上面组件中的state并不是绑定在组件的函数上的,而是在组件渲染产生的虚拟DOM节点,也就是 FiberNode 上的。在上面的函数中调用 useState,意味着函数将访问函数本身以外、React以内的状态,这就让函数产生了副作用,导致不再是纯函数。或者说:state不是函数参数中的,把它绑定在组件对应的虚拟DOM节点并返回,对函数组件来说相当于外部状态,因此因为useState Hook 使得函数组件不再是纯函数。
总结
加入Hooks的函数组件不再纯粹,但更加的强大,因为Hooks的出现使得函数式组件可以使用包括state以内的、React的大部分特性。更好的状态管理,更妙的副作用处理、可玩性更高的自定义hooks。(后续可能会写着部分内容)